diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 00000000..f0018ca9 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,575 @@ +{ + "projectName": "castopod", + "projectOwner": "adaures", + "repoType": "gitlab", + "repoHost": "https://code.castopod.org", + "files": ["README.md"], + "imageSize": 100, + "commit": false, + "contributors": [ + { + "login": "yassinedoghri", + "name": "Yassine Doghri", + "avatar_url": "https://avatars.githubusercontent.com/u/11021441?v=4", + "profile": "https://yassinedoghri.com", + "contributions": [ + "code", + "bug", + "doc", + "review", + "maintenance", + "content", + "design", + "a11y", + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "question", + "mentoring", + "infra", + "ideas", + "projectManagement", + { + "type": "blog", + "url": "https://blog.castopod.org/author/yassinedoghri/" + } + ] + }, + { + "login": "benjamin", + "name": "Benjamin Bellamy", + "avatar_url": "https://code.castopod.org/uploads/-/system/user/avatar/2/avatar.png", + "profile": "https://code.castopod.org/benjamin", + "contributions": [ + "code", + "bug", + "review", + "content", + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "question", + "infra", + "ideas", + { + "type": "blog", + "url": "https://blog.castopod.org/author/benjamin-bellamy/" + }, + "projectManagement", + "talk" + ] + }, + { + "login": "ola", + "name": "Ola Hneini", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://github.com/ola-hn", + "contributions": [ + "code", + "review", + "doc", + "maintenance", + "question", + "ideas" + ] + }, + { + "login": "rdelaage", + "name": "Romain de Laage", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://mamot.fr/@rdelaage", + "contributions": [ + "code", + "infra", + "doc", + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "ideas" + ] + }, + { + "login": "Lyonel", + "name": "Lyonel Bernard", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://twitter.com/lyonelbernard", + "contributions": ["bug", "question", "audio", "ideas"] + }, + { + "login": "ctlw83", + "name": "Christopher Lagonick-Weitzel", + "avatar_url": "https://secure.gravatar.com/avatar/7c2a721b52d0763673a600e8f01bd745?s=80&d=identicon", + "profile": "https://www.crypticchameleon.com/", + "contributions": ["bug", "question", "audio", "ideas"] + }, + { + "login": "ernestoacostame", + "name": "Ernesto Acosta", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://ernestoacosta.me/", + "contributions": [ + "bug", + "audio", + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "question", + "ideas" + ] + }, + { + "login": "3wen", + "name": "Ewen", + "avatar_url": "https://mastodon.fedi.bzh/system/accounts/avatars/000/000/002/original/6f387690a504ae46.jpg", + "profile": "https://mastodon.fedi.bzh/@ewen", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "ideas", + "code" + ] + }, + { + "login": "Behel", + "name": "Bastien Luneteau", + "avatar_url": "https://secure.gravatar.com/avatar/ad63ee8ef8e3db8253d21e5012d2724f?s=80&d=identicon", + "profile": "https://code.castopod.org/Behel", + "contributions": ["code", "bug"] + }, + { + "login": "cecillie", + "name": "Cécile Ricordeau", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://www.cecillie.fr/", + "contributions": ["design"] + }, + { + "login": "PatrykMis", + "name": "Patryk Miś", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/PatrykMis", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "mspanc", + "name": "Marcin Lewandowski", + "avatar_url": "https://secure.gravatar.com/avatar/eed8337939641eac5ad0b570bd6acf96?s=80&d=identicon", + "profile": "https://code.castopod.org/mspanc", + "contributions": ["bug", "ideas"] + }, + { + "login": "SJanik", + "name": "Sebastian Janik", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/SJanik", + "contributions": ["code"] + }, + { + "login": "patryk", + "name": "Patryk Karczmarczyk", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/patryk", + "contributions": ["code"] + }, + { + "login": "ddenis", + "name": "denis d", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/ddenis", + "contributions": ["bug", "ideas"] + }, + { + "login": "douglaskastle", + "name": "Douglas Kastle", + "avatar_url": "https://secure.gravatar.com/avatar/b7e652ba4b6bcd440afa069e7f7bc9e6?s=80&d=identicon", + "profile": "https://code.castopod.org/douglaskastle", + "contributions": ["bug", "ideas"] + }, + { + "login": "cExplorer", + "name": "cExplorer", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/cExplorer", + "contributions": [ + "bug", + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "imacrea", + "name": "ImaCrea", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/imacrea", + "contributions": ["bug", "ideas"] + }, + { + "login": "jonas", + "name": "Jonas S", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/jonas", + "contributions": ["code"] + }, + { + "login": "yannL", + "name": "LEFEBVRE Yann", + "avatar_url": "https://secure.gravatar.com/avatar/9c46600ce566ec6d526370d8e104b1c8?s=80&d=identicon", + "profile": "https://code.castopod.org/yannL", + "contributions": ["bug"] + }, + { + "login": "spaetz", + "name": "Sebastian Späth", + "avatar_url": "https://secure.gravatar.com/avatar/278e1af65e82993efd0ba7bbbacf6435?s=80&d=identicon", + "profile": "https://code.castopod.org/spaetz", + "contributions": ["bug", "ideas"] + }, + { + "login": "rocky", + "name": "rocky III", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/rocky", + "contributions": ["bug"] + }, + { + "login": "Regenpfeifer", + "name": "Hermann Josef Eckl", + "avatar_url": "https://code.castopod.org/uploads/-/system/user/avatar/103/avatar.png", + "profile": "https://code.castopod.org/Regenpfeifer", + "contributions": ["bug"] + }, + { + "login": "cyrilledel", + "name": "Delhaye Cyrille", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://code.castopod.org/cyrilledel", + "contributions": ["bug", "ideas"] + }, + { + "login": "otetranome", + "name": "João Leandro", + "avatar_url": "https://code.castopod.org/uploads/-/system/user/avatar/113/avatar.png", + "profile": "https://twitter.com/otetranome", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + }, + "ideas" + ] + }, + { + "login": "achouvardas", + "name": "Angelos Chouvardas", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://achouvardas.eu/", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "eivind", + "name": "Eivind", + "avatar_url": "https://mastodon.fjerland.no/system/accounts/avatars/107/769/768/295/192/222/original/e5c985fea6487dcb.jpg", + "profile": "https://mastodon.fjerland.no/@eivind", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "forght", + "name": "forght", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15073833/large/82d1e2e443a6df7edc43a7405dfeeb75_default.png", + "profile": "https://crowdin.com/profile/forght", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "glottis0q", + "name": "glottis0q", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15209934/large/8b17ef6a7399f0b82a8198f87c224195.png", + "profile": "https://crowdin.com/profile/glottis0q", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "BoFFire", + "name": "ButterflyOfFire", + "avatar_url": "https://static.mstdn.fr/static/accounts/avatars/000/065/901/original/5908e93ad5447f15.png", + "profile": "https://mstdn.fr/@ButterflyOfFire", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "lil5", + "name": "Lucian I. Last", + "avatar_url": "https://avatars.githubusercontent.com/u/17646836?v=4", + "profile": "https://github.com/lil5", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "LuuzViir", + "name": "LuuzViir", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/13166188/large/d03ab0abc7ce354b210d836955cd3805_default.png", + "profile": "https://crowdin.com/profile/luuzviir", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "cthtc", + "name": "CTHTC", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15211502/large/ed0651060cb8474a9519b5168bd377c1_default.png", + "profile": "https://crowdin.com/profile/cthtc", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "retrograde", + "name": "Russian Retro", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15021651/large/b10c4057f85bf4de49c7fdf01354ecde.jpeg", + "profile": "https://crowdin.com/profile/retrograde", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "mareklach", + "name": "Marek L'ach", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/13572324/large/3eeba8d569c247ace33862bf4ef4748f.jpeg", + "profile": "https://crowdin.com/profile/mareklach", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "GunChleoc", + "name": "GunChleoc", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/13043878/large/3223f7b606296a8b1c92c5de39c459a2_default.png", + "profile": "https://crowdin.com/profile/gunchleoc", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "GabiSnow", + "name": "GabiSnow", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15214858/large/5b083bdf9c9e9de67cc6ee72a6c8db18_default.png", + "profile": "https://crowdin.com/profile/gabisnow", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "bendaha", + "name": "bendaha", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15331656/large/cd92450d2c20202299fb3a0075903e20_default.png", + "profile": "https://crowdin.com/profile/bendaha", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "samuelroland", + "name": "Samuel Roland", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/14980053/large/3e154a37d03d6e98ae402ed3f930f4f5.png", + "profile": "https://crowdin.com/profile/samuelroland", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "dimregnier", + "name": "Dimitri Regnier", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://dimitriregnier.net/", + "contributions": ["ideas"] + }, + { + "login": "irithys", + "name": "irithys", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15405614/large/3086461c47cce0a0c031925e5f943412.png", + "profile": "https://im.irithys.com/@thy", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "caos30", + "name": "Sergi", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://twitter.com/caos30", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "basen1982", + "name": "Andreas Olsson", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://crowdin.com/profile/basen1982", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "leonfrom", + "name": "leonfrom", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://crowdin.com/profile/leonfrom", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "agentcobra57", + "name": "agentcobra", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://crowdin.com/profile/agentcobra57", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "alephoto85", + "name": "Alessandro", + "avatar_url": "https://crowdin-static.downloads.crowdin.com/avatar/15094649/large/530391f54157af52ae33058ec15b0f99.jpg", + "profile": "https://crowdin.com/profile/alephoto85", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "liimee", + "name": "liimee", + "avatar_url": "https://castopod.org/assets/images/castopod-avatar.jpg", + "profile": "https://crowdin.com/profile/liimee", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "ahmedsabouni", + "name": "Ahmed Sabouni", + "avatar_url": "https://avatars.githubusercontent.com/u/74497842?v=4", + "profile": "https://github.com/ahmedsabouni", + "contributions": [ + { + "type": "translation", + "url": "https://translate.castopod.org" + } + ] + }, + { + "login": "KrzysztofDomanczyk", + "name": "KrzysztofDomanczyk", + "avatar_url": "https://avatars.githubusercontent.com/u/75178474?v=4", + "profile": "https://github.com/KrzysztofDomanczyk", + "contributions": ["code"] + }, + { + "login": "Dwev", + "name": "Guy Martin", + "avatar_url": "https://avatars.githubusercontent.com/u/46626050?v=4", + "profile": "https://github.com/Dwev", + "contributions": ["bug", "code"] + }, + { + "login": "prcutler", + "name": "Paul Cutler", + "avatar_url": "https://avatars.githubusercontent.com/u/67276?v=4", + "profile": "https://github.com/prcutler", + "contributions": ["doc", "question", "ideas"] + }, + { + "login": "nateritter", + "name": "Nate Ritter", + "avatar_url": "https://avatars.githubusercontent.com/u/198798?v=4", + "profile": "https://github.com/nateritter", + "contributions": ["code"] + } + ], + "commitConvention": "none" +} diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..cca42fb0 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,50 @@ +#################################################### +# Castopod development Docker file +#################################################### +# ⚠️ NOT optimized for production +# should be used only for development purposes +#--------------------------------------------------- +FROM php:8.5-fpm + +LABEL maintainer="Yassine Doghri " + +# Install composer +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +# Install server requirements +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get update \ + && apt-get install --yes --no-install-recommends nodejs \ + # gnupg to sign commits with gpg + gnupg \ + openssh-client \ + # cron for scheduled tasks + cron \ + # unzip used by composer + unzip \ + # required libraries to install php extensions using + # https://github.com/mlocati/docker-php-extension-installer (included in php's docker image) + libicu-dev \ + libpng-dev \ + libwebp-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + zlib1g-dev \ + libzip-dev \ + # ffmpeg for video encoding + ffmpeg \ + # intl for Internationalization + && docker-php-ext-install intl \ + && docker-php-ext-install zip \ + # gd for image processing + && docker-php-ext-configure gd --with-webp --with-jpeg --with-freetype \ + && docker-php-ext-install gd \ + && docker-php-ext-install exif \ + && docker-php-ext-enable exif \ + # redis extension for cache + && pecl install -o -f redis \ + && rm -rf /tmp/pear \ + && docker-php-ext-enable redis \ + # mysqli for database access + && docker-php-ext-install mysqli \ + && docker-php-ext-enable mysqli diff --git a/.devcontainer/crontab b/.devcontainer/crontab new file mode 100644 index 00000000..8cef165a --- /dev/null +++ b/.devcontainer/crontab @@ -0,0 +1 @@ +* * * * * /usr/local/bin/php /workspaces/castopod/spark tasks:run >> /dev/null 2>&1 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 71a8104d..f1c12034 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,41 +1,70 @@ // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.117.1/containers/docker-existing-dockerfile { - "name": "Castopod Host dev", - "dockerComposeFile": ["../docker-compose.yml", "./docker-compose.yml"], + "name": "castopod.local", + "dockerComposeFile": ["./docker-compose.yml"], "service": "app", - "workspaceFolder": "/castopod-host", - "postCreateCommand": "composer install && npm install && npm run build:static", - "postStartCommand": "crontab ./crontab && cron && php spark serve --host 0.0.0.0", - "postAttachCommand": "crontab ./crontab && service cron reload", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "postCreateCommand": "composer install && pnpm install && pnpm run build:static && php spark migrate --all && php spark db:seed DevSeeder", + "postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && crontab .devcontainer/crontab && cron && php spark serve --host 0.0.0.0 --port ${APP_PORT:-8080}", + "postAttachCommand": "crontab .devcontainer/crontab && service cron reload", "shutdownAction": "stopCompose", - "settings": { - "terminal.integrated.defaultProfile.linux": "bash", - "editor.formatOnSave": true, - "[php]": { - "editor.defaultFormatter": "bmewburn.vscode-intelephense-client", - "editor.formatOnSave": false - }, - "color-highlight.markerType": "dot-before", - "files.associations": { - "*.xml.dist": "xml", - "spark": "php" - } + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/guiyomh/features/vim:0": {}, + "ghcr.io/NicoVIII/devcontainer-features/pnpm:2": {} }, - "extensions": [ - "mikestead.dotenv", - "bmewburn.vscode-intelephense-client", - "streetsidesoftware.code-spell-checker", - "naumovs.color-highlight", - "heybourn.headwind", - "wayou.vscode-todo-highlight", - "esbenp.prettier-vscode", - "bradlc.vscode-tailwindcss", - "jamesbirtles.svelte-vscode", - "dbaeumer.vscode-eslint", - "stylelint.vscode-stylelint", - "eamodio.gitlens", - "breezelin.phpstan", - "kasik96.latte" - ] + "customizations": { + "vscode": { + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[php]": { + "editor.defaultFormatter": "bmewburn.vscode-intelephense-client", + "editor.formatOnSave": false + }, + "css.validate": false, + "color-highlight.markerType": "dot-before", + "files.associations": { + "*.xml.dist": "xml", + "spark": "php", + "env": "dotenv", + ".rsync-filter": "diff" + }, + "json.schemas": [ + { + "fileMatch": [ + "plugins/**/manifest.json", + "tests/modules/Plugins/mocks/manifests/*.json", + "tests/modules/Plugins/mocks/plugins/**/manifest.json" + ], + "url": "/workspaces/castopod/modules/Plugins/Manifest/manifest.schema.json" + } + ] + }, + "extensions": [ + "astro-build.astro-vscode", + "bmewburn.vscode-intelephense-client", + "bradlc.vscode-tailwindcss", + "breezelin.phpstan", + "DavidAnson.vscode-markdownlint", + "dbaeumer.vscode-eslint", + "eamodio.gitlens", + "esbenp.prettier-vscode", + "heybourn.headwind", + "jamesbirtles.svelte-vscode", + "kasik96.latte", + "mikestead.dotenv", + "naumovs.color-highlight", + "pflannery.vscode-versionlens", + "runem.lit-plugin", + "streetsidesoftware.code-spell-checker", + "stylelint.vscode-stylelint", + "unifiedjs.vscode-mdx", + "wayou.vscode-todo-highlight", + "yzhang.markdown-all-in-one", + "42Crunch.vscode-openapi" + ] + } + } } diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index c7323a5b..665b78e9 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,10 +1,76 @@ -version: "3" services: app: + build: + context: . + dockerfile: Dockerfile volumes: - # Mounts the project folder to '/workspace'. While this file is in .devcontainer, - # mounts are relative to the first file in the list, which is a level up. - - .:/castopod-host:cached + - ../..:/workspaces:cached + - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini + environment: + APP_PORT: ${APP_PORT:-8080} # used in devcontainer.json file + VITE_PORT: ${VITE_PORT:-5173} # used in ../vite.config.js file + CI_ENVIRONMENT: development + vite_environment: development + app_forceGlobalSecureRequests: 0 #false + app_baseURL: http://localhost:${APP_PORT:-8080}/ + media_baseURL: http://localhost:${APP_PORT:-8080}/ + admin_gateway: cp-admin + auth_gateway: cp-auth + analytics_salt: dev_analytics_salt + database_default_hostname: mariadb + database_default_database: castopod + database_default_username: castopod + database_default_password: castopod + database_default_DBPrefix: cp_ + restapi_enabled: 1 #true + email_fromEmail: hello@castopod.local + email_SMTPCrypto: "" + email_SMTPHost: mailpit + email_SMTPUser: castopod + email_SMTPPass: castopod + email_SMTPPort: ${MAILPIT_SMTP_PORT:-1025} + depends_on: + - mariadb - # Overrides default command so things don't shut down after the process ends. - command: /bin/sh -c "while sleep 1000; do :; done" + mariadb: + image: mariadb:10.2 + volumes: + - ./initdb:/docker-entrypoint-initdb.d + - mariadb:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: castopod + MYSQL_USER: castopod + MYSQL_PASSWORD: castopod + + phpmyadmin: + image: phpmyadmin/phpmyadmin:latest + environment: + PMA_HOST: mariadb + PMA_PORT: 3306 + UPLOAD_LIMIT: 300M + ports: + - 8888:80 + volumes: + - phpmyadmin:/sessions + depends_on: + - mariadb + + mailpit: + image: axllent/mailpit + restart: always + volumes: + - mailpit:/data + ports: + - ${MAILPIT_WEBUI_PORT:-8025}:8025 + - ${MAILPIT_SMTP_PORT:-1025}:1025 + environment: + MP_MAX_MESSAGES: 5000 + MP_DATA_FILE: /data/mailpit.db + MP_SMTP_AUTH_ACCEPT_ANY: 1 + MP_SMTP_AUTH_ALLOW_INSECURE: 1 + +volumes: + mariadb: + phpmyadmin: + mailpit: diff --git a/.devcontainer/initdb/01.sql b/.devcontainer/initdb/01.sql new file mode 100644 index 00000000..2429cc61 --- /dev/null +++ b/.devcontainer/initdb/01.sql @@ -0,0 +1,2 @@ +CREATE DATABASE IF NOT EXISTS `test`; +GRANT ALL ON `test`.* TO 'castopod'@'%'; diff --git a/.devcontainer/uploads.ini b/.devcontainer/uploads.ini new file mode 100644 index 00000000..23b3c1cd --- /dev/null +++ b/.devcontainer/uploads.ini @@ -0,0 +1,5 @@ +file_uploads = On +memory_limit = 512M +upload_max_filesize = 500M +post_max_size = 512M +max_execution_time = 300 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..1b773dc8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,68 @@ +.env + +.git/ +node_modules/ +vendor/ +build/ +docs/ +scripts/ +tests/ + +#------------------------- +# Temporary Files +#------------------------- +writable/cache/* +!writable/cache/index.html + +writable/logs/* +!writable/logs/index.html + +writable/session/* +!writable/session/index.html + +writable/temp/* +!writable/temp/index.html + +writable/uploads/* +!writable/uploads/index.html + +writable/debugbar/* +!writable/debugbar/index.html + +# public folder +public/* +!public/media +!public/.htaccess +!public/favicon.ico +!public/icon* +!public/castopod-banner* +!public/castopod-avatar* +!public/index.php +!public/robots.txt +!public/.well-known +!public/.well-known/GDPR.yml + +public/assets/* +!public/assets/index.html + +# public media folder +!public/media/podcasts +!public/media/persons +!public/media/site + +public/media/podcasts/* +!public/media/podcasts/index.html + +public/media/persons/* +!public/media/persons/index.html + +public/media/site/* +!public/media/site/index.html + +# Generated files +modules/Admin/Language/*/PersonsTaxonomy.php + +# Castopod bundle & packages +castopod/ +castopod-*.zip +castopod-*.tar.gz diff --git a/.env.example b/.env.example index ca3f31a2..40e4c336 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ # Example Environment Configuration file # # This file can be used as a starting point for -# your Castopod Host instance settings. +# your Castopod instance settings. # # For manual configuration: # - copy this file's contents to a file named `.env` @@ -14,9 +14,10 @@ # Instance configuration #-------------------------------------------------------------------- app.baseURL="https://YOUR_DOMAIN_NAME/" -app.mediaBaseURL="https://YOUR_MEDIA_DOMAIN_NAME/" -app.adminGateway="cp-admin" -app.authGateway="cp-auth" +media.baseURL="https://YOUR_MEDIA_DOMAIN_NAME/" +admin.gateway="cp-admin" +auth.gateway="cp-auth" +analytics.salt="RANDOM_STRING_OF_64_CHARACTERS" #-------------------------------------------------------------------- # Database configuration @@ -27,6 +28,14 @@ database.default.username="root" database.default.password="****" database.default.DBPrefix="cp_" +#-------------------------------------------------------------------- +# Email configuration +#-------------------------------------------------------------------- +# email.fromEmail="your_email_address" +# email.SMTPHost="your_smtp_host" +# email.SMTPUser="your_smtp_user" +# email.SMTPPass="your_smtp_password" + #-------------------------------------------------------------------- # Cache configuration (advanced) # @@ -41,3 +50,21 @@ cache.handler="file" # cache.redis.password=null # cache.redis.port=6379 # cache.redis.database=0 + +#-------------------------------------------------------------------- +# S3 configuration +#-------------------------------------------------------------------- +# media.fileManager="s3" +# media.s3.endpoint="your_s3_host" +# media.s3.key="your_s3_key" +# media.s3.secret="your_s3_secret" +# media.s3.region="your_s3_region" + +#-------------------------------------------------------------------- +# REST API configuration +#-------------------------------------------------------------------- +# restapi.enabled=true +# restapi.basicAuthUsername=castopod +# restapi.basicAuthPassword=password +# restapi.basicAuth=true + diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index cff4e85e..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "env": { - "browser": true, - "es2020": true - }, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended" - ], - "parserOptions": { - "ecmaVersion": 11, - "sourceType": "module" - }, - "rules": {} -} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..47b10567 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: castopod diff --git a/.gitignore b/.gitignore index 29ac934c..b7ea048c 100644 --- a/.gitignore +++ b/.gitignore @@ -60,10 +60,14 @@ writable/logs/* writable/session/* !writable/session/index.html +writable/temp/* +!writable/temp/index.html + writable/uploads/* !writable/uploads/index.html writable/debugbar/* +!writable/debugbar/index.html php_errors.log @@ -82,6 +86,7 @@ tests/coverage* # Don't save phpunit under version control. phpunit +.phpunit.cache #------------------------- # Composer @@ -102,15 +107,15 @@ _modules/* .idea/ *.iml -# Netbeans -nbproject/ -build/ -nbbuild/ -dist/ -nbdist/ -nbactions.xml -nb-configuration.xml -.nb-gradle/ +# NetBeans +/nbproject/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/nbactions.xml +/nb-configuration.xml +/.nb-gradle/ # Sublime Text *.tmlanguage.cache @@ -123,14 +128,16 @@ nb-configuration.xml # Visual Studio Code .vscode/ +.history/ +tmp/ /results/ /phpunit*.xml -/.phpunit.*.cache -# npm +# js package manager yarn.lock node_modules +.pnpm-store # JS .cache @@ -140,14 +147,21 @@ public/* !public/media !public/.htaccess !public/favicon.ico +!public/icon* +!public/castopod-banner* +!public/castopod-avatar* !public/index.php !public/robots.txt +!public/.well-known +!public/.well-known/GDPR.yml + +public/assets/* +!public/assets/index.html # public media folder -public/media/* -!public/media/index.html !public/media/podcasts !public/media/persons +!public/media/site public/media/podcasts/* !public/media/podcasts/index.html @@ -155,19 +169,19 @@ public/media/podcasts/* public/media/persons/* !public/media/persons/index.html +public/media/site/* +!public/media/site/index.html + # Generated files -app/Language/en/PersonsTaxonomy.php -app/Language/fr/PersonsTaxonomy.php +modules/Admin/Language/*/PersonsTaxonomy.php -#------------------------- -# Docker volumes -#------------------------- +# Castopod bundle & packages +castopod/ +castopod-*.zip +castopod-*.tar.gz -mariadb -phpmyadmin -sessions - -# Castopod Host bundle & packages -castopod-host/ -castopod-host-*.zip -castopod-host-*.tar.gz +# Plugins +plugins/* +!plugins/.gitkeep +writable/plugins.json +writable/plugins-lock.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10f35381..32076043 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,30 +1,52 @@ -image: code.podlibre.org:5050/podlibre/castopod-host:latest +image: code.castopod.org:5050/adaures/castopod:ci-php8.5 stages: - prepare - quality - bundle - release + - deploy + - build php-dependencies: stage: prepare script: # Install all php dependencies - composer install --prefer-dist --no-ansi --no-interaction --no-progress --ignore-platform-reqs + cache: + key: + files: + - composer.lock + paths: + - .composer-cache artifacts: + expire_in: 30 mins paths: - vendor/ - expire_in: 30 mins + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success js-dependencies: stage: prepare script: - # Install all npm dependencies - - npm ci + # Install all js dependencies + - pnpm install + cache: + key: + files: + - pnpm-lock.yaml + paths: + - .pnpm-store artifacts: + expire_in: 30 mins paths: - node_modules/ - expire_in: 30 mins + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success lint-commit-msg: stage: quality @@ -34,6 +56,10 @@ lint-commit-msg: - ./scripts/lint-commit-msg.sh dependencies: - js-dependencies + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - if: $CI_COMMIT_BRANCH =~ /^(develop|main|alpha|beta|next)$/ lint-php: stage: quality @@ -46,25 +72,46 @@ lint-php: - vendor/bin/rector process --dry-run --ansi dependencies: - php-dependencies + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success lint-js: stage: quality script: - - npm run prettier - - npm run typecheck - - npm run lint - - npm run lint:css + - pnpm run format + - pnpm run typecheck + - pnpm run lint + - pnpm run lint:css dependencies: - js-dependencies + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success tests: stage: quality + services: + - mariadb:10.11 + variables: + MYSQL_ROOT_PASSWORD: "R00Tp4ssW0RD" + MYSQL_DATABASE: "test" + MYSQL_USER: "castopod" + MYSQL_PASSWORD: "castopod" script: + - echo "SHOW DATABASES;" | mariadb --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mariadb "$MYSQL_DATABASE" --skip_ssl + # run phpunit without code coverage # TODO: add code coverage - vendor/bin/phpunit --no-coverage dependencies: - php-dependencies + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success bundle: stage: bundle @@ -76,19 +123,21 @@ bundle: # make scripts/bundle.sh executable - chmod +x ./scripts/bundle.sh - # bundle castopod-host with commit ref as version + # bundle castopod with commit ref as version - ./scripts/bundle.sh ${CI_COMMIT_REF_SLUG}_${CI_COMMIT_SHORT_SHA} dependencies: - php-dependencies - js-dependencies artifacts: - name: "castopod-host-${CI_COMMIT_REF_SLUG}_${CI_COMMIT_SHORT_SHA}" + name: "castopod-${CI_COMMIT_REF_SLUG}_${CI_COMMIT_SHORT_SHA}" paths: - - castopod-host - except: - - main - - beta - - alpha + - castopod + rules: + - if: $CI_PROJECT_NAMESPACE != "adaures" + when: never + - if: $CI_COMMIT_BRANCH =~ /^(main|alpha|beta|next)$/ || $CI_COMMIT_TAG + when: never + - when: on_success release: stage: release @@ -105,11 +154,45 @@ release: - chmod +x ./scripts/package.sh # run semantic-release script (configured in `.releaserc.json` file) - - npm run release + - pnpm run release dependencies: - php-dependencies - js-dependencies - only: - - main - - alpha - - beta + artifacts: + paths: + - castopod + rules: + - if: $CI_PROJECT_NAMESPACE != "adaures" + when: never + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - if: $CI_COMMIT_BRANCH =~ /^(main|alpha|beta|next)$/ + +website: + stage: deploy + trigger: adaures/castopod.org + rules: + - if: $CI_PROJECT_NAMESPACE != "adaures" + when: never + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ && $CI_COMMIT_TAG + +documentation: + stage: deploy + trigger: + include: docs/.gitlab-ci.yml + strategy: depend + rules: + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ + when: never + - when: on_success + +docker: + stage: build + trigger: + include: docker/production/.gitlab-ci.yml + strategy: depend + rules: + - if: $CI_PROJECT_NAMESPACE != "adaures" + when: never + - if: $CI_COMMIT_BRANCH == "develop" + - if: $CI_COMMIT_MESSAGE =~ /^chore\(release\):/ && $CI_COMMIT_TAG diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md index 7fec749a..c6041a61 100644 --- a/.gitlab/issue_templates/bug.md +++ b/.gitlab/issue_templates/bug.md @@ -6,7 +6,7 @@ 1. [First step] 2. [Second step] -3. [and so on...] +3. [and so on…] ### Expected behavior @@ -27,7 +27,7 @@ logs, and code as it's very hard to read otherwise. - OS: [e.g. Ubuntu server] - Browser: [e.g. chrome, safari] - Web server: [eg. Apache] -- [any other relevant context...] +- [any other relevant context…] ### Possible fixes diff --git a/.gitlab/issue_templates/default.md b/.gitlab/issue_templates/default.md new file mode 100644 index 00000000..e806744e --- /dev/null +++ b/.gitlab/issue_templates/default.md @@ -0,0 +1,17 @@ +### Before submitting an issue + +1. **Use the issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + latest release. + +3. **Isolate the problem** — ideally create a + [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live + example. + +4. **Select an issue template** — choose a template from `bug` or + `feature-request` and fill out the info you deem necessary. The more context + we get, the easier it is to implement the feature or fix the bug you report. + +Check out the [CONTRIBUTING manual](../../CONTRIBUTING.md) for more info. diff --git a/.gitlab/issue_templates/feature-request.md b/.gitlab/issue_templates/feature-request.md index 644a8fd4..0886d392 100644 --- a/.gitlab/issue_templates/feature-request.md +++ b/.gitlab/issue_templates/feature-request.md @@ -1,7 +1,7 @@ ### Is your feature request related to a problem? Please describe A clear and concise description of what the problem is. Ex. I'm always -frustrated when [...] +frustrated when […] ### Describe the solution you'd like diff --git a/.husky/commit-msg b/.husky/commit-msg index cdb7c8da..062719b1 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no-install commitlint --verbose --edit "$1" +pnpm exec commitlint --verbose --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit index 39c89b16..12ee980f 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,11 +1,8 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - # CaptainHook 5.10.0 INTERACTIVE="--no-interaction" vendor/bin/captainhook $INTERACTIVE --configuration=captainhook.json --bootstrap=vendor/autoload.php hook:pre-commit "$@" <&0 -npm run typecheck -npx lint-staged +pnpm run typecheck +pnpm exec lint-staged diff --git a/.husky/pre-push b/.husky/pre-push index 9b4d0f80..a3617f04 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,6 +1,3 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - # CaptainHook 5.10.0 INTERACTIVE="--no-interaction" diff --git a/.prettierrc.json b/.prettierrc.json index d567a64c..cae76d94 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -2,7 +2,7 @@ "trailingComma": "es5", "overrides": [ { - "files": "*.md", + "files": ["*.md", "*.mdx"], "options": { "proseWrap": "always" } diff --git a/.releaserc.json b/.releaserc.json index e5e8267a..7a8b6584 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,17 +1,86 @@ { "branches": [ "main", - { "name": "alpha", "prerelease": true }, - { "name": "beta", "prerelease": true } + { + "name": "alpha", + "prerelease": true + }, + { + "name": "beta", + "prerelease": true + }, + { + "name": "next", + "prerelease": true + } ], "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { + "type": "docs", + "scope": "README", + "release": "patch" + }, + { + "type": "refactor", + "scope": "core-*", + "release": "minor" + }, + { + "type": "refactor", + "release": "patch" + } + ], + "parserOpts": { + "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"] + } + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "parserOpts": { + "noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"] + }, + "presetConfig": { + "types": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "chore", + "section": "Internal", + "hidden": false + }, + { + "type": "refactor", + "section": "Internal", + "hidden": false + }, + { + "type": "perf", + "section": "Internal", + "hidden": false + } + ] + } + } + ], "@semantic-release/changelog", [ "@semantic-release/exec", { - "prepareCmd": "./scripts/bundle.sh ${nextRelease.version} && ./scripts/package.sh ${nextRelease.version} && npx prettier --write CHANGELOG.md" + "prepareCmd": "./scripts/bundle.sh ${nextRelease.version} && ./scripts/package.sh ${nextRelease.version} && pnpm exec prettier --write CHANGELOG.md" } ], "@semantic-release/npm", @@ -24,21 +93,22 @@ "package.json", "package-lock.json", "CHANGELOG.md" - ] + ], + "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" } ], [ "@semantic-release/gitlab", { - "gitlabUrl": "https://code.podlibre.org/", + "gitlabUrl": "https://code.castopod.org/", "assets": [ { - "path": "castopod-host-*.zip", - "label": "Castopod Host Package (zip)" + "path": "castopod-*.zip", + "label": "Castopod Package (zip)" }, { - "path": "castopod-host-*.tar.gz", - "label": "Castopod Host Package (tar.gz)" + "path": "castopod-*.tar.gz", + "label": "Castopod Package (tar.gz)" } ] } diff --git a/.rsync-filter b/.rsync-filter index e1308e5d..0fcb79ec 100644 --- a/.rsync-filter +++ b/.rsync-filter @@ -1,14 +1,17 @@ -# rsync filter rules to copy required files for Castopod Host's bundle +# rsync filter rules to copy required files for Castopod's bundle -- app/Views/_assets/ ++ resources/icons/*** ++ resources/ + app/*** ++ modules/*** ++ plugins/*** + public/*** ++ themes/*** + vendor/*** + writable/*** + .env.example -+ DEPENDENCIES.md + LICENSE.md + README.md -+ INSTALL.md -+ UPDATE.md ++ spark ++ php-icons.php - ** diff --git a/.stylelintrc.json b/.stylelintrc.json index 2cd0132c..8ea025c1 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,5 +1,5 @@ { - "extends": "stylelint-config-recommended", + "extends": "stylelint-config-standard", "rules": { "at-rule-no-unknown": [ true, @@ -10,10 +10,24 @@ "responsive", "variants", "screen", - "layer" + "layer", + "config" ] } ], - "no-descending-specificity": null + "at-rule-no-deprecated": [ + true, + { + "ignoreAtRules": ["apply"] + } + ], + "function-no-unknown": [ + true, + { + "ignoreFunctions": ["theme"] + } + ], + "no-descending-specificity": null, + "selector-class-pattern": null } } diff --git a/.svgo.js b/.svgo.cjs similarity index 100% rename from .svgo.js rename to .svgo.cjs diff --git a/.svgo.icons.js b/.svgo.icons.cjs similarity index 100% rename from .svgo.icons.js rename to .svgo.icons.cjs diff --git a/AUTHORS.md b/AUTHORS.md index 137ec914..a716c5ba 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,4 +1,4 @@ # Authors -- [Benjamin Bellamy](https://code.podlibre.org/benjamin) -- [Yassine Doghri](https://code.podlibre.org/yassine) +- [Benjamin Bellamy](https://code.castopod.org/benjamin) +- [Yassine Doghri](https://code.castopod.org/yassine) diff --git a/CHANGELOG.md b/CHANGELOG.md index 417a822f..29f4a170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,868 +1,3887 @@ -# [1.0.0-alpha.80](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.79...v1.0.0-alpha.80) (2021-12-29) +## [2.0.0-next.3](https://code.castopod.org/adaures/castopod/compare/v2.0.0-next.2...v2.0.0-next.3) (2024-12-30) + +### Features + +- **api:** add Episode create and publish endpoints + ([a90cdfd](https://code.castopod.org/adaures/castopod/commit/a90cdfdcdbde7a8fb520c6815d7b757947aea055)) +- **image:** add image size's width and height + ([f50098e](https://code.castopod.org/adaures/castopod/commit/f50098ec8926c8ae40718f5f128b6de7fe721b46)) +- **plugins:** add defaultValue for all field types + ([d3a98db](https://code.castopod.org/adaures/castopod/commit/d3a98db6d0112b5f59daddd2708c09dd2e595332)) +- **plugins:** add group field type + multiple option to render field arrays + ([11ccd0e](https://code.castopod.org/adaures/castopod/commit/11ccd0ebe71d476d8c0dbfe28edcf01f7f362b83)) +- **plugins:** add html field type + CodeEditor component + rework html head + generation + ([8cf9c6d](https://code.castopod.org/adaures/castopod/commit/8cf9c6dc833aedcccbc4cdb309b111f84d97d629)) +- **rss:** add option for 301 redirect to new feed url + ([8402cc2](https://code.castopod.org/adaures/castopod/commit/8402cc29d2d0c61b014a7e03e5ccce7d3c11782a)) ### Bug Fixes +- add downloads_count to episodes table, computed every hour + ([f981937](https://code.castopod.org/adaures/castopod/commit/f9819376455c371eb5bd3c84ad938698335a3d67)) +- allow passing json to app.proxyIPs config to set it + ([cbf739e](https://code.castopod.org/adaures/castopod/commit/cbf739e95cc0ad6e83a21353b8f4678e68d74f63)) +- **api:** cast integers when creating episode + ([775b302](https://code.castopod.org/adaures/castopod/commit/775b302f7c886e30e133c8a8c68764301b6c663b)) +- **docker-image:** clear cache to account for new assets and data structure + changes + ([63c763f](https://code.castopod.org/adaures/castopod/commit/63c763f941195b3758c4b91acd8c350a5e7bb9c2)), + closes [#510](https://code.castopod.org/adaures/castopod/issues/510) +- edit remap functions to get episode in episode admin controllers + ([9f74cca](https://code.castopod.org/adaures/castopod/commit/9f74cca342fedd896977efd2e89d0143959f3c4f)) +- **episode:** do not change slug when editing episode title + ([a83afb0](https://code.castopod.org/adaures/castopod/commit/a83afb0004511db80337806577fbc36f8d777116)), + closes [#513](https://code.castopod.org/adaures/castopod/issues/513) +- **fediverse:** add "processing" and "failed" statuses to better manage + broadcast load + ([1d7583d](https://code.castopod.org/adaures/castopod/commit/1d7583d738219574ae3d45d294dc94e7e406472b)), + closes [#511](https://code.castopod.org/adaures/castopod/issues/511) +- **icons:** set correct names for lock and lock-unlock icons in premium banner + ([37ee6d3](https://code.castopod.org/adaures/castopod/commit/37ee6d35b4bb66ce23dc271fb846200d1be0e7f6)) +- **plugins:** clear cache after activating or deactivating plugin + ([08c7df2](https://code.castopod.org/adaures/castopod/commit/08c7df2a5d5be340490c78deeef823167eb1b2fc)) +- **plugins:** delete relevant cache when submitting settings + ([00bd4c0](https://code.castopod.org/adaures/castopod/commit/00bd4c02ee23b181d74e7731626bfec3b1ff4916)) +- **podcast-model:** always query podcast from database when clearing cache + ([d30c49c](https://code.castopod.org/adaures/castopod/commit/d30c49cdff380c15db4f1851631a255a5baffcbe)) +- **premium-podcasts:** update query to validate subscription + ([2b1bbf3](https://code.castopod.org/adaures/castopod/commit/2b1bbf34303ead927f433b5c7d5d888ca3799954)) +- **preview:** delete episode preview cache after editing episode + ([732d429](https://code.castopod.org/adaures/castopod/commit/732d42923d0d7a66ff1ebd5841458e4205060560)), + closes [#514](https://code.castopod.org/adaures/castopod/issues/514) +- **release:** add conventional-changelog-conventionalcommits for CHANGELOG + generation + ([6934c8a](https://code.castopod.org/adaures/castopod/commit/6934c8aa8f0b7f9eea7c3f6f4089c56b2391d9a6)) +- **rss:** add subscription id to cache name to prevent premium feeds from + overlapping + ([74f9325](https://code.castopod.org/adaures/castopod/commit/74f9325946d03a0d4efce57045e41cc9454ff97c)) +- set user as www-data when running cron jobs in docker's supervisord config + ([65d74f1](https://code.castopod.org/adaures/castopod/commit/65d74f14e612be3757c9304518eee112705f5ff9)) +- typo in EpisodeController remap function to get episode + ([f288a75](https://code.castopod.org/adaures/castopod/commit/f288a750f580ab19b04a170cc76bf8769084e19d)) +- update select and multi-select options to value/label arrays + ([63f93f5](https://code.castopod.org/adaures/castopod/commit/63f93f585bec4a11022cc8c75deb34968cba2348)) + +### Internal + +- **plugins:** create Field objects per field type in settings forms + handle + rendering in class + ([34be5bc](https://code.castopod.org/adaures/castopod/commit/34be5bccabb7531afdcc6ebaf1dd39e4dfbe0677)) +- remove fields from podcast and episode entities to be replaced with plugins + ([b869acb](https://code.castopod.org/adaures/castopod/commit/b869acb3a988a3616d883a41c25d9c8409bd5518)) +- rename controller methods for views and actions to be more consistent + ([85704bf](https://code.castopod.org/adaures/castopod/commit/85704bfbe03fe5e38ff5e76a0e1cf0e5f1275f57)) +- update CodeIgniter to v4.5.6 + ([f295e9a](https://code.castopod.org/adaures/castopod/commit/f295e9aa4ca3129df24a22779f7c19bba7fac370)) +- update codigniter-icons to v1.0.1 + ([fa6967e](https://code.castopod.org/adaures/castopod/commit/fa6967e65cef1705b19cbb205132c4c751507d53)) +- update js dependencies to latest + ([70c9797](https://code.castopod.org/adaures/castopod/commit/70c97971fcf5bbeee826578057ae0e3afbbbd8a8)) + +# [2.0.0-next.2](https://code.castopod.org/adaures/castopod/compare/v2.0.0-next.1...v2.0.0-next.2) (2024-07-08) + +### Bug Fixes + +- **audio-player:** set player icons to default instead of missing Castopod's + ([0ba0a25](https://code.castopod.org/adaures/castopod/commit/0ba0a25b11bd67aeeb47a8179b72152dfd4a36da)) +- broken icon call in frontend default pages template + ([3228362](https://code.castopod.org/adaures/castopod/commit/322836254e86be7878e21438177ee8f73f03a2fa)) +- **manifest:** set repository url as required in docstring typings + ([a8c81b3](https://code.castopod.org/adaures/castopod/commit/a8c81b3fa19a28dbd608027c231dcac31eafb38f)) +- set correct icons parameters in map and funding links views + ([5d35524](https://code.castopod.org/adaures/castopod/commit/5d355248753be24e3cf324144ff076f2fc23be88)), + closes [#500](https://code.castopod.org/adaures/castopod/issues/500) + +### Features + +- **plugins:** add `minCastopodVersion` to denote incompatibility with previous + Castopod versions + ([fc9ea75](https://code.castopod.org/adaures/castopod/commit/fc9ea7597e454e5c7c7af043d29af7bbe119e342)) +- **plugins:** load and display LICENSE.md file if found in plugin's directory + ([fee7905](https://code.castopod.org/adaures/castopod/commit/fee7905935a9adf963b4485b437fe4d972c14b5f)) + +# [2.0.0-next.1](https://code.castopod.org/adaures/castopod/compare/v1.11.0...v2.0.0-next.1) (6/19/2024) + +### Bug Fixes + +- add missing php-icons config file to bundle + ([56612f0](https://code.castopod.org/adaures/castopod/commit/56612f0c762aa2d98e3c8c77fba88ffdf6f46a44)) +- **docs:** add base to og image using env variable + ([fe67659](https://code.castopod.org/adaures/castopod/commit/fe676590f23a33bdbe8905d234760923c029e350)) +- **import:** rewrite download_file helper to output curl response directly to + file + ([eb7ad2f](https://code.castopod.org/adaures/castopod/commit/eb7ad2f7e1c0137f222f47e47062887de42c4824)) +- include app/Resources/icons folder to bundle + ([3fd5efc](https://code.castopod.org/adaures/castopod/commit/3fd5efc7956977acc19e53182f25b12813964a7d)) +- **platforms:** add platforms service + reduce memory consumption when + rendering platform cards + ([fe73e9f](https://code.castopod.org/adaures/castopod/commit/fe73e9fae9ea5d5ce946680aec194308bb2e620c)) +- set owner email visibility when editing podcast + ([fc4f982](https://code.castopod.org/adaures/castopod/commit/fc4f9825568cd4384c5b3cfe972accd146548807)), + closes [#473](https://code.castopod.org/adaures/castopod/issues/473) + +### Build System + +- release next major version as prerelease + ([8275226](https://code.castopod.org/adaures/castopod/commit/827522643e9f8a5ea9be05b4847dc637f0f43a13)) + +### Features + +- add Plugins module with base files for plugins architecture + ([7253e13](https://code.castopod.org/adaures/castopod/commit/7253e13ac2118f6f165f54ea0cbcd63d51ab9205)) +- **plugins:** abstract settings form for general, podcast and episode types + ([b62b483](https://code.castopod.org/adaures/castopod/commit/b62b483ad9ff114a22a9ee52e1a1a2c9fa444d42)) +- **plugins:** activate / deactivate plugin using settings table + ([27d2a1b](https://code.castopod.org/adaures/castopod/commit/27d2a1b0ffba9454dd54cbb4251a2d179b09762a)) +- **plugins:** add aside with plugin metadata next to plugin's readme + ([dfb7888](https://code.castopod.org/adaures/castopod/commit/dfb7888aeb689b4066abc37084e08cd7f1d0f15d)) +- **plugins:** add before channel/item hooks to allow podcast/episode data edit + when generating rss + ([80d2c48](https://code.castopod.org/adaures/castopod/commit/80d2c48ee265cb32ed0d710c488292fcbc120044)) +- **plugins:** add json schema definition for plugin manifest + ([b5eddf3](https://code.castopod.org/adaures/castopod/commit/b5eddf351f6f6fa1c299fbac31cbd056ef232330)) +- **plugins:** add methods to easily retrieve general, podcast and episode + settings in hooks methods + ([3a900bb](https://code.castopod.org/adaures/castopod/commit/3a900bbab68b819cedf8943540d2ee0aeb6e8539)) +- **plugins:** add new field types + validate & cast user data before storing + settings + ([6f833fc](https://code.castopod.org/adaures/castopod/commit/6f833fc76a3aa6c6b87c27ad18a2fb90e537e21e)) +- **plugins:** add options to manifest for building forms and storing plugin + settings + ([3d8aedf](https://code.castopod.org/adaures/castopod/commit/3d8aedf9c34e6927b6d3b11445d5f0e669b347d7)) +- **plugins:** add settings page for podcast and episode if defined in the + plugin's manifest + ([89ac92f](https://code.castopod.org/adaures/castopod/commit/89ac92fb412a04231ce52fd6480c9ab893b19ef5)) +- **plugins:** add siteHead hook to add custom meta tags to public pages + ([e80a33b](https://code.castopod.org/adaures/castopod/commit/e80a33bf2ad4fe1b47037add7470a6c2770f4036)) +- **plugins:** display errors when plugin is invalid instead of crashing + ([8ec7909](https://code.castopod.org/adaures/castopod/commit/8ec79097bbdbcbce622518ef61c068f20e0ef74e)) +- **plugins:** handle empty states and long strings in UI + ([45ac2a4](https://code.castopod.org/adaures/castopod/commit/45ac2a4be96532b9456e6af1d26ba4ada3649303)) +- **plugins:** load and validate plugin manifest.json + ([1510e36](https://code.castopod.org/adaures/castopod/commit/1510e36c0acd2b254622ec230acd1d2461ee9bf3)) +- **plugins:** load plugins using file locator service + ([587938d](https://code.castopod.org/adaures/castopod/commit/587938d2bf307b823af143586b9ec9e9b44e8dc1)) +- **plugins:** load README.md file to view plugin's instructions in UI + ([e6bfdfc](https://code.castopod.org/adaures/castopod/commit/e6bfdfc3902705285701c13c8067fe0f538425c6)) +- **plugins:** register plugins using Plugin.php file instead of namespace + + simplify i18n structure + ([2035c39](https://code.castopod.org/adaures/castopod/commit/2035c39fd138a1fd408516bd1972ab6a02544c10)) +- **plugins:** uninstall plugins via CLI and admin UI + ([9a80de4](https://code.castopod.org/adaures/castopod/commit/9a80de40686bbf4288da21cc2a6dde8036580e47)) +- set owner email to hidden by default in podcast create form + ([7a6d9df](https://code.castopod.org/adaures/castopod/commit/7a6d9df6db8a6184b8250ced0475f3e741dde7f4)) +- support podcast:txt tag with verify use case + ([57e459e](https://code.castopod.org/adaures/castopod/commit/57e459e187ed048430f4137172e22396cd02bf81)), + closes [#468](https://code.castopod.org/adaures/castopod/issues/468) + +### BREAKING CHANGES + +- next major release including plugins architecture + +# [1.11.0](https://code.castopod.org/adaures/castopod/compare/v1.10.5...v1.11.0) (4/17/2024) + +### Bug Fixes + +- **premium:** set itunes:block on premium feeds to prevent indexing + ([88851b0](https://code.castopod.org/adaures/castopod/commit/88851b022663d575a816f0e2f33f0353767dd52d)) +- **rss:** generate podcast guid if empty + ([a5aef2a](https://code.castopod.org/adaures/castopod/commit/a5aef2a63e464632f3941649d455672835989e6c)), + closes [#450](https://code.castopod.org/adaures/castopod/issues/450) + +### Features + +- add trailer tags to rss if trailer episodes are present + ([80fdd9c](https://code.castopod.org/adaures/castopod/commit/80fdd9cfb4a95feac6ed0000435a013fc83e6892)) +- add transcript display to episode page + ([4d141fc](https://code.castopod.org/adaures/castopod/commit/4d141fceae56fa9e666b42c32a830ff9c68989db)), + closes [#411](https://code.castopod.org/adaures/castopod/issues/411) +- **platforms:** add telegram to socials + ([004f804](https://code.castopod.org/adaures/castopod/commit/004f804045cd8e884361bb4318109fbdd7afc9a8)) +- **platforms:** add truefans.fm and episodes.fm + ([d046ecc](https://code.castopod.org/adaures/castopod/commit/d046ecc52f6ccd41d09f6de48e00d2c61d25d7f0)), + closes [#458](https://code.castopod.org/adaures/castopod/issues/458) + [#459](https://code.castopod.org/adaures/castopod/issues/459) + +## [1.10.5](https://code.castopod.org/adaures/castopod/compare/v1.10.4...v1.10.5) (3/12/2024) + +### Bug Fixes + +- **file-uploads:** validate chapters json content + remove permit_empty rule to + uploaded files + ([6289c42](https://code.castopod.org/adaures/castopod/commit/6289c42b1189f074c7e4e4cd9fbfd73bf26625c9)), + closes [#445](https://code.castopod.org/adaures/castopod/issues/445) + +## [1.10.4](https://code.castopod.org/adaures/castopod/compare/v1.10.3...v1.10.4) (2/26/2024) + +### Bug Fixes + +- display chapters in episode preview page + ([797516a](https://code.castopod.org/adaures/castopod/commit/797516a2ec7d88704412a5cca50421e8eef38eec)), + closes [#445](https://code.castopod.org/adaures/castopod/issues/445) + +## [1.10.3](https://code.castopod.org/adaures/castopod/compare/v1.10.2...v1.10.3) (2/21/2024) + +### Bug Fixes + +- **chapters:** use episode cover when chapter img is an empty string + ([a343de4](https://code.castopod.org/adaures/castopod/commit/a343de4cf6ba38561b8fe675fa9c38d9f0ecfec7)), + closes [#444](https://code.castopod.org/adaures/castopod/issues/444) +- **import:** set episodes as premium if podcast is set as premium by default + ([dfd66be](https://code.castopod.org/adaures/castopod/commit/dfd66beebfcca1670b0a9d389e8e3f8d2d08d2f2)) + +## [1.10.2](https://code.castopod.org/adaures/castopod/compare/v1.10.1...v1.10.2) (2/20/2024) + +### Bug Fixes + +- **podcast-import:** move closing parenthasis when checking for owner name and + email existence + ([cec7815](https://code.castopod.org/adaures/castopod/commit/cec78155f94a222edcf7964c0a2f3a3e0f46a98d)) + +## [1.10.1](https://code.castopod.org/adaures/castopod/compare/v1.10.0...v1.10.1) (2/20/2024) + +### Bug Fixes + +- **fediverse:** use config name to get Fediverse config properties instead of + hardcoded class string + ([5fd0980](https://code.castopod.org/adaures/castopod/commit/5fd0980ff7101d45051a2daa3f635694f85609d7)) + +# [1.10.0](https://code.castopod.org/adaures/castopod/compare/v1.9.0...v1.10.0) (2/19/2024) + +### Bug Fixes + +- **op3:** move op3 prefix to enclosure url instead of audio proxy + ([d580369](https://code.castopod.org/adaures/castopod/commit/d5803692357952d82d54efd8d3aa71de3a1c9571)) +- **podcast-import:** rollback transaction before exception is thrown + ([419bb04](https://code.castopod.org/adaures/castopod/commit/419bb04716088586b87b2c8f24a954ca8cfd6c76)), + closes [#429](https://code.castopod.org/adaures/castopod/issues/429) + [#319](https://code.castopod.org/adaures/castopod/issues/319) + [#443](https://code.castopod.org/adaures/castopod/issues/443) + [#438](https://code.castopod.org/adaures/castopod/issues/438) + +### Features + +- add podcast:season and podcast:episode tags to rss feed + ([98c6658](https://code.castopod.org/adaures/castopod/commit/98c6658840eedd55bd6d8042f8a69c342b87cd71)) +- add support for podcasting 2.0 "medium" tag with podcast, music and audiobook + ([630e788](https://code.castopod.org/adaures/castopod/commit/630e788f0e1ddfe5de229bd415a8e15361efa746)), + closes [#439](https://code.castopod.org/adaures/castopod/issues/439) +- display chapters in episode's public page + ([87cc437](https://code.castopod.org/adaures/castopod/commit/87cc437e1ead5486ed46ca37e2055aaf5c9445c1)), + closes [#423](https://code.castopod.org/adaures/castopod/issues/423) +- support VTT transcript file format in addition to SRT + ([7071b4b](https://code.castopod.org/adaures/castopod/commit/7071b4b6f48cb9a2f766064f3a5c23f92b293718)), + closes [#433](https://code.castopod.org/adaures/castopod/issues/433) + +# [1.9.0](https://code.castopod.org/adaures/castopod/compare/v1.8.2...v1.9.0) (1/31/2024) + +### Bug Fixes + +- **i18n:** escape language strings in form fields to prevent them from + disappearing + ([3cb5ffd](https://code.castopod.org/adaures/castopod/commit/3cb5ffd25b9604a83cd12935e641dab7c88fba47)), + closes [#412](https://code.castopod.org/adaures/castopod/issues/412) +- **podcast-about:** update stats query to discard scheduled episodes from + episodes number + ([67c037c](https://code.castopod.org/adaures/castopod/commit/67c037c9eb1e15c6945eaf74ec0ff30b33f4b704)) +- **premium-subs:** clear subscription list cache after insert + ([2accb0f](https://code.castopod.org/adaures/castopod/commit/2accb0f7652330b29c3adb85a2e1b0d5d83f1389)), + closes [#430](https://code.castopod.org/adaures/castopod/issues/430) +- **s3:** remove proxy, set objects acl to public-read, and serve files using + their public urls + ([6a77a9d](https://code.castopod.org/adaures/castopod/commit/6a77a9d2f29c849775a3d1bcbd819f73f21d9aa6)) + +### Features + +- add actor domain to handle in follow page + ([de099ac](https://code.castopod.org/adaures/castopod/commit/de099ac64300b8edb86e387fde89c0a3e9472f46)) +- **admin:** add podcast's OP3 analytics dashboard link + ([5f3752b](https://code.castopod.org/adaures/castopod/commit/5f3752b4430f6f2d5f9e5f6a7a003bc4d2f9d487)) + +## [1.8.2](https://code.castopod.org/adaures/castopod/compare/v1.8.1...v1.8.2) (1/17/2024) + +### Bug Fixes + +- **transcript:** add condition when concatenating sub text to prevent second + line duplication + ([6cbfec0](https://code.castopod.org/adaures/castopod/commit/6cbfec0d7d9bf85c8014d379026648857ea13373)) + +## [1.8.1](https://code.castopod.org/adaures/castopod/compare/v1.8.0...v1.8.1) (1/16/2024) + +### Bug Fixes + +- **models:** set updatedField as empty string when not used + ([164f4d3](https://code.castopod.org/adaures/castopod/commit/164f4d3be74ec8d371fb40d7fe730f7b2940ca05)) + +# [1.8.0](https://code.castopod.org/adaures/castopod/compare/v1.7.4...v1.8.0) (1/15/2024) + +### Bug Fixes + +- **episode-form:** add required validation rules for title and slug + ([30a3473](https://code.castopod.org/adaures/castopod/commit/30a34738635bf4f4a4c6b2a7174f7e439f0dfc6e)), + closes [#420](https://code.castopod.org/adaures/castopod/issues/420) +- **import:** check for empty string when generating podcast guid for feeds not + including one + ([ac5336f](https://code.castopod.org/adaures/castopod/commit/ac5336fbc5fb8038de541dd06938a8beb2e8d733)) +- **install:** add created superadmin to most powerful group in instance, ie. + superadmin + ([2ed511f](https://code.castopod.org/adaures/castopod/commit/2ed511f8a0005dc06eda5afd6b1d13beee1eb9dd)) +- **persons:** delete person avatar when deleting a person + ([c1ec98c](https://code.castopod.org/adaures/castopod/commit/c1ec98c95656844712011ff30b84c397b78da311)), + closes [#419](https://code.castopod.org/adaures/castopod/issues/419) +- **platforms:** add matrix.org as a social platform + ([9178c3f](https://code.castopod.org/adaures/castopod/commit/9178c3f3afa16e104d25ae159728e90a3bbd57c3)), + closes [#421](https://code.castopod.org/adaures/castopod/issues/421) + +### Features + +- **admin:** add tooltip for not authorized routes + ([f7f9baf](https://code.castopod.org/adaures/castopod/commit/f7f9bafc3e56621fab2569d9d76baafe0a2e940d)) +- **admin:** emphasize unprivileged items in sidebar with "prohibited" icon + ([0bd7dde](https://code.castopod.org/adaures/castopod/commit/0bd7ddea58adf502121b83e5c09317e20912fb4e)) +- allow hiding owner's email in public RSS feed + ([222e02a](https://code.castopod.org/adaures/castopod/commit/222e02a2af9ecb8b8768a63d3054f4c3ef54e991)) +- **persons:** order persons by full_name ASC for easier list scanning + ([68a599f](https://code.castopod.org/adaures/castopod/commit/68a599fee08c71763b9336e14b1c0d9e28c4449b)), + closes [#418](https://code.castopod.org/adaures/castopod/issues/418) + +## [1.7.4](https://code.castopod.org/adaures/castopod/compare/v1.7.3...v1.7.4) (1/3/2024) + +### Bug Fixes + +- **media:** add missing HEAD route for static assets served with S3 + ([b61a32c](https://code.castopod.org/adaures/castopod/commit/b61a32c8a9b10e129666804d533487430ce7432c)) + +## [1.7.3](https://code.castopod.org/adaures/castopod/compare/v1.7.2...v1.7.3) (12/21/2023) + +### Bug Fixes + +- **analytics:** upgrade opawg's user-agents-php to user-agents-v2-php + ([8cd7886](https://code.castopod.org/adaures/castopod/commit/8cd78866762e26aa63c224dace6c247e0e9dc068)) +- **platforms:** add Threads and YouTube Music + ([9264a2d](https://code.castopod.org/adaures/castopod/commit/9264a2d74cc95278c9d84c99ef914fdbcaf8a97f)) + +## [1.7.2](https://code.castopod.org/adaures/castopod/compare/v1.7.1...v1.7.2) (12/12/2023) + +### Bug Fixes + +- **episode-form:** render episode number optional when episode type is trailer + or bonus + ([694328f](https://code.castopod.org/adaures/castopod/commit/694328f10865b2fcd6436122de46866dae81f945)) + +## [1.7.1](https://code.castopod.org/adaures/castopod/compare/v1.7.0...v1.7.1) (12/1/2023) + +### Bug Fixes + +- **housekeeping:** add where clause to check episode_id is not null on reset + comments count + ([119742c](https://code.castopod.org/adaures/castopod/commit/119742cdbb2c2f7f847692fb76f6ff1dbb2e25b6)) + +# [1.7.0](https://code.castopod.org/adaures/castopod/compare/v1.6.5...v1.7.0) (11/29/2023) + +### Bug Fixes + +- **admin-ux:** hide navigation submenus in details panel for easier scanning + ([b047a3c](https://code.castopod.org/adaures/castopod/commit/b047a3c6707114d04c276758f2e543eef90d72f5)) +- **admin:** remove episode title truncation + display description in two lines + in episode list + ([f4ffa30](https://code.castopod.org/adaures/castopod/commit/f4ffa30ec4341f43e22b1f983781ad04c956aa25)), + closes [#386](https://code.castopod.org/adaures/castopod/issues/386) +- **auth:** display error messages from validator + ([5a834c0](https://code.castopod.org/adaures/castopod/commit/5a834c0f8957fc016e73325a3c3ff05e524d0755)) +- **housekeeping:** remove unnecessary $tablePrefix variable when resetting post + count + ([97d793f](https://code.castopod.org/adaures/castopod/commit/97d793f55e7eb3b049980e5081950baa2bb1b881)), + closes [#383](https://code.castopod.org/adaures/castopod/issues/383) +- **import:** handle bad values for location attributes + ([642981f](https://code.castopod.org/adaures/castopod/commit/642981fd358ccf118d3d7a957fb6be7933c016ac)) +- **import:** use cocur/slugify library to handle non latin text + ([4ca7f9c](https://code.castopod.org/adaures/castopod/commit/4ca7f9ccae1e352bf26a3b6db4de73bac7b84382)) +- move monetization outside of podcast form + add broadcast section to podcast + menu + ([dff8516](https://code.castopod.org/adaures/castopod/commit/dff85168b32a6df77425ef51865588ebcd8b8ba9)) +- **nodeinfo2:** import database config + use dynamic table prefix for active + local actors query + ([6a7ef01](https://code.castopod.org/adaures/castopod/commit/6a7ef0109a6e52144ca687b979ffe56fba66165b)) +- **persons:** set roles field as optional + set `Cast > Host` as default value + ([02132dc](https://code.castopod.org/adaures/castopod/commit/02132dc46640807e2bc4cfc406c911fa097f36fe)), + closes [#347](https://code.castopod.org/adaures/castopod/issues/347) +- **platforms:** make platforms' websites and submit urls more prominent + ([61cf8fa](https://code.castopod.org/adaures/castopod/commit/61cf8fa3e2435ee2a9bdd8e711b8d69d4ca4ec4c)) +- **podcast-form:** move fediverse section below author section + ([1861d67](https://code.castopod.org/adaures/castopod/commit/1861d67971e2cc0c20ace091f037f6436437a50d)) +- reorder podcast form fields + extract sync feeds to its own form + ([2d52fa1](https://code.castopod.org/adaures/castopod/commit/2d52fa1046faf1b8d81304e35fc24a7874315e6e)) + +### Features + +- **admin:** add rss feed link to podcast side navigation + ([18e2633](https://code.castopod.org/adaures/castopod/commit/18e2633a49dbbeb57a685f129a2ab158397de61e)) +- **icons:** update new Deezer logo + ([f2d5b27](https://code.castopod.org/adaures/castopod/commit/f2d5b272ac385a978d7e173121faafe03d7a7200)) +- **install:** init database and create superadmin using CLI + ([02d4ba6](https://code.castopod.org/adaures/castopod/commit/02d4ba69ac007ebd1eccab428a98b54051aaf70c)), + closes [#380](https://code.castopod.org/adaures/castopod/issues/380) +- **ux:** add episode description to episode cards + ([5f8d413](https://code.castopod.org/adaures/castopod/commit/5f8d413b84b236077a75934da9409f37d34cb4a5)) + +## [1.6.5](https://code.castopod.org/adaures/castopod/compare/v1.6.4...v1.6.5) (2023-09-26) + +### Bug Fixes + +- **fediverse:** use NoteObject including episode link in content (hotfix) + ([ffa530e](https://code.castopod.org/adaures/castopod/commit/ffa530e187ff6488648a7cf749ca0173765a5d87)) + +## [1.6.4](https://code.castopod.org/adaures/castopod/compare/v1.6.3...v1.6.4) (2023-09-17) + +### Bug Fixes + +- **fediverse:** do not cache remote action form + fix typo on post routes for + passing post uuid + ([4ecb42f](https://code.castopod.org/adaures/castopod/commit/4ecb42f7c82eb8d41d27c7b9705b3278ea04ab79)) +- **fediverse:** update post controller namespace in routes + ([3189f12](https://code.castopod.org/adaures/castopod/commit/3189f122067dc47d6de93c3185aca66d7df95e1a)) + +## [1.6.3](https://code.castopod.org/adaures/castopod/compare/v1.6.2...v1.6.3) (2023-09-14) + +### Bug Fixes + +- **fediverse:** add `index` to post controller-method to access post's jsonld + contents + ([35142d8](https://code.castopod.org/adaures/castopod/commit/35142d8e565e828a977ba2b4de77c1b47a633beb)) + +## [1.6.2](https://code.castopod.org/adaures/castopod/compare/v1.6.1...v1.6.2) (2023-09-11) + +### Bug Fixes + +- **migrations:** remove if exists modifier for drop index + ([82013c9](https://code.castopod.org/adaures/castopod/commit/82013c9cde901c54fdb3a833890aa693e8542627)), + closes [#382](https://code.castopod.org/adaures/castopod/issues/382) + +## [1.6.1](https://code.castopod.org/adaures/castopod/compare/v1.6.0...v1.6.1) (2023-09-09) + +### Bug Fixes + +- **admin:** redirect root fediverse route to fediverse-blocked-actors + ([ba5324e](https://code.castopod.org/adaures/castopod/commit/ba5324ea1942a3939f186e974d29fb393c54b253)) +- **analytics:** show full referrer domain in web pages visits reports + ([6be38e9](https://code.castopod.org/adaures/castopod/commit/6be38e9fda3d1436d81686e1a3a5e5b173e390a0)), + closes [#367](https://code.castopod.org/adaures/castopod/issues/367) +- **auth:** overwrite Shield's PermissionFilter + ([c6e8000](https://code.castopod.org/adaures/castopod/commit/c6e8000bab54f4a32068578f750f4cf9d91bad89)) +- **auth:** update shield from v1.0.0-beta.3 to v1.0.0-beta.6 + ([23842df](https://code.castopod.org/adaures/castopod/commit/23842df03ae28e416390e2436442b8e7c8340333)) +- **platforms:** add missing tiktok to social platforms seed + ([8dfdaf3](https://code.castopod.org/adaures/castopod/commit/8dfdaf321566050e9c53683e70864871eb55d618)) +- remove fediverse prefix to prevent migration error + load routes during + podcast import + ([7ff1dbe](https://code.castopod.org/adaures/castopod/commit/7ff1dbe9030768074b2fe7c7f570bfb9e7336f62)) +- **routes:** overwrite RouteCollection to include all routes + update js and + php dependencies + ([b4f1b91](https://code.castopod.org/adaures/castopod/commit/b4f1b916bfec53f071e8d0d900081c6d74486e53)) +- update Router to include latest CI changes with alternate-content logic + ([ae57601](https://code.castopod.org/adaures/castopod/commit/ae57601c838a7aa9469bae8038ac1c30d8c9a51e)) +- use podcast-activity named route instead of not existing actor route + ([3c35718](https://code.castopod.org/adaures/castopod/commit/3c357183ca51545787fcfc801b4a5829d9cd8ad6)) + +# [1.6.0](https://code.castopod.org/adaures/castopod/compare/v1.5.2...v1.6.0) (2023-08-28) + +### Bug Fixes + +- **home:** update where clause when getting all podcasts to prevent draft + podcasts from showing up + ([7a1eea5](https://code.castopod.org/adaures/castopod/commit/7a1eea58d3cbc1982baaec21d87a36e218e1910a)) +- **media:** copy and delete temp file when saving instead of moving it for FS + FileManager + ([9346e78](https://code.castopod.org/adaures/castopod/commit/9346e787bd2a2c815533092279f96ae1fe0d9aae)), + closes [#338](https://code.castopod.org/adaures/castopod/issues/338) +- **media:** get path using media_path_absolute when saving media file + ([754e7a6](https://code.castopod.org/adaures/castopod/commit/754e7a6b4b2c12cf50c1c8b166732dc3255f36fb)) +- **media:** init file properties in setAttributes' Model method + set defaults + to pathinfo data + ([0775add](https://code.castopod.org/adaures/castopod/commit/0775add67860b94a35b68c01b133ec8ec969f539)) +- **premium-podcasts:** show premium flag only when podcast has published + premium episodes + ([d10c4fd](https://code.castopod.org/adaures/castopod/commit/d10c4fd7538e6af8a5b0eb232a06522fe8c4bf8e)) +- **s3:** add a flag to serve media files by redirecting to a presigned url + instead of default proxy + ([11aa358](https://code.castopod.org/adaures/castopod/commit/11aa3586a04c166404954600235634cee77219df)) + +### Features + +- **episode:** add preview link in admin to view and share episode before + publication + ([7d21b35](https://code.castopod.org/adaures/castopod/commit/7d21b3509ec5d1aa65420efa038f44bcd235e64f)) + +## [1.5.2](https://code.castopod.org/adaures/castopod/compare/v1.5.1...v1.5.2) (2023-07-31) + +### Bug Fixes + +- **credits:** remove undefined $podcast variable from page layout + ([73a5b68](https://code.castopod.org/adaures/castopod/commit/73a5b680875cc520fd15c529c01d44df728f9be2)), + closes [#359](https://code.castopod.org/adaures/castopod/issues/359) +- **platforms:** change twitter to X + add buymeacoffee and kofi as funding + ([d69b4e4](https://code.castopod.org/adaures/castopod/commit/d69b4e4857fcb1ac1c05ac59c78d130788f00400)), + closes [#353](https://code.castopod.org/adaures/castopod/issues/353) + [#361](https://code.castopod.org/adaures/castopod/issues/361) + +## [1.5.1](https://code.castopod.org/adaures/castopod/compare/v1.5.0...v1.5.1) (2023-07-29) + +### Bug Fixes + +- **admin-ui:** remove button labels on smaller screens in podcast view + ([9cc5ffd](https://code.castopod.org/adaures/castopod/commit/9cc5ffd1439fdc86f46a03f4319cae32db95f84e)) +- **rss:** set srt transcripts' mimetype to application/x-subrip with + rel="captions" attribute + ([16a3fdb](https://code.castopod.org/adaures/castopod/commit/16a3fdb56e3f07185e75d106216f29519ccb25f7)), + closes [#360](https://code.castopod.org/adaures/castopod/issues/360) +- **rss:** update podcast extension namespace + ([6833dd0](https://code.castopod.org/adaures/castopod/commit/6833dd05ab51bc530d34fd4174ad732f623226c0)), + closes [#360](https://code.castopod.org/adaures/castopod/issues/360) + +# [1.5.0](https://code.castopod.org/adaures/castopod/compare/v1.4.7...v1.5.0) (2023-07-27) + +### Bug Fixes + +- **admin-ui:** truncate header title + remove sticky podcast banner card on + mobile + ([63c20da](https://code.castopod.org/adaures/castopod/commit/63c20da5ffd500265f06fa38f2b2c963e14602af)) + +### Features + +- add podcast links page including social, podcasting and funding links + ([8ae2929](https://code.castopod.org/adaures/castopod/commit/8ae292933af15fa99856582ac24e985bfef37d5b)) + +## [1.4.7](https://code.castopod.org/adaures/castopod/compare/v1.4.6...v1.4.7) (2023-07-19) + +### Bug Fixes + +- **s3:** allow CORS for served static files + ([9b955c9](https://code.castopod.org/adaures/castopod/commit/9b955c9ce25a06a9102b67ebe77375dc45d28f0f)) + +## [1.4.6](https://code.castopod.org/adaures/castopod/compare/v1.4.5...v1.4.6) (2023-07-11) + +### Bug Fixes + +- **fediverse:** expand object before sending accept follow request + ([082cdc9](https://code.castopod.org/adaures/castopod/commit/082cdc9ee79d004c2ed748e3b8046e9141bf0242)), + closes [#350](https://code.castopod.org/adaures/castopod/issues/350) +- **podcast-import:** remove error log when no import in queue, exit with + success instead + ([5e719f3](https://code.castopod.org/adaures/castopod/commit/5e719f3e9eb6cf48c3fd8ac97181638b24d03fc9)) + +## [1.4.5](https://code.castopod.org/adaures/castopod/compare/v1.4.4...v1.4.5) (2023-07-04) + +### Bug Fixes + +- **s3:** handle range requests to serve media files + ([41a5932](https://code.castopod.org/adaures/castopod/commit/41a59322332c835808a32987aaf8ec6cafbf5fca)) + +## [1.4.4](https://code.castopod.org/adaures/castopod/compare/v1.4.3...v1.4.4) (2023-07-02) + +### Bug Fixes + +- **audio-clipper:** init segment position on firstUpdate + improve UX by adding + ghost handle + ([aa68386](https://code.castopod.org/adaures/castopod/commit/aa683866671d14c0b9a11b09c74eb132673e5547)), + closes [#351](https://code.castopod.org/adaures/castopod/issues/351) +- set resized images to 72dpi for compatibility with Apple Podcasts + ([0b327cb](https://code.castopod.org/adaures/castopod/commit/0b327cb4d9c92d0ae227a0f08ede3b29390df172)), + closes [#282](https://code.castopod.org/adaures/castopod/issues/282) + +## [1.4.3](https://code.castopod.org/adaures/castopod/compare/v1.4.2...v1.4.3) (2023-06-29) + +### Bug Fixes + +- **video-clipper:** add -t option to ffmpeg command to stop generation after + duration + ([60814b8](https://code.castopod.org/adaures/castopod/commit/60814b8d202419c2bdbf6abb7c2bde447537b7e9)), + closes [#341](https://code.castopod.org/adaures/castopod/issues/341) + +## [1.4.2](https://code.castopod.org/adaures/castopod/compare/v1.4.1...v1.4.2) (2023-06-27) + +### Bug Fixes + +- **fediverse:** check that actor's images mimetype is present or guess it + otherwise + ([06c4f15](https://code.castopod.org/adaures/castopod/commit/06c4f15477a568407a3d3c1e5e489bc0241bc1e9)), + closes [#348](https://code.castopod.org/adaures/castopod/issues/348) +- **podcast-import:** show cancel or retry action depending on task status + ([e42258d](https://code.castopod.org/adaures/castopod/commit/e42258de1f331aac0cbb380b80cd8fc7f9d7dc18)) + +## [1.4.1](https://code.castopod.org/adaures/castopod/compare/v1.4.0...v1.4.1) (2023-06-22) + +### Bug Fixes + +- **podcast-import:** set default values for person group and role if not found + in taxonomy + ([aa46dca](https://code.castopod.org/adaures/castopod/commit/aa46dca4e399bf2e544d62dcb4a9a0328e4e6c41)) + +# [1.4.0](https://code.castopod.org/adaures/castopod/compare/v1.3.5...v1.4.0) (2023-06-21) + +### Bug Fixes + +- **charts:** set duration charts label to HHhMM for listening time analytics + ([3fc1d8e](https://code.castopod.org/adaures/castopod/commit/3fc1d8e18dc8119251c72dcaa7e5121246c2b194)) +- **embed:** set height of player iframe from config + ([4665741](https://code.castopod.org/adaures/castopod/commit/4665741425532f253a46a42ba05602047798dba2)) +- **s3:** serve files without cache if dummy cache handler + add http referer + header to redirect + ([30db9f0](https://code.castopod.org/adaures/castopod/commit/30db9f0667bf7f7a5f186ea667a524d1e3b502db)) +- **s3:** use presigned request uri to serve static files + ([cb92dc7](https://code.castopod.org/adaures/castopod/commit/cb92dc73f17543d32d1cdc24db72403a5c561a74)) +- **webmanifest:** import misc helper to get site_icon_url + ([548a11d](https://code.castopod.org/adaures/castopod/commit/548a11d501749fa61ef894fd8818abae5668554f)) + +### Features + +- **import:** run podcast imports' processes asynchronously using tasks + ([d8e1d40](https://code.castopod.org/adaures/castopod/commit/d8e1d4031d86de9a3889b74ae2a6d9c90af8a1da)) +- **rest-api:** add endpoints for episodes and full text search for podcasts and + episodes + ([85505d4](https://code.castopod.org/adaures/castopod/commit/85505d4b3181c96bc91619e3ab9b0601f8e1c120)), + closes [#296](https://code.castopod.org/adaures/castopod/issues/296) + +## [1.3.5](https://code.castopod.org/adaures/castopod/compare/v1.3.4...v1.3.5) (2023-05-09) + +### Bug Fixes + +- replace essence with embera to create preview cards + ([c682f03](https://code.castopod.org/adaures/castopod/commit/c682f03a67c6c0ebbcc6ff45d9a037f6f9823bde)) + +## [1.3.4](https://code.castopod.org/adaures/castopod/compare/v1.3.3...v1.3.4) (2023-05-05) + +### Bug Fixes + +- **import-update:** insert episodes incrementally into database + ([108fdf8](https://code.castopod.org/adaures/castopod/commit/108fdf84b8dd458fc71a06a77d14069287ab8e42)) + +## [1.3.3](https://code.castopod.org/adaures/castopod/compare/v1.3.2...v1.3.3) (2023-04-17) + +### Bug Fixes + +- unnescape podcast title special characters in "find us on" section + ([f727276](https://code.castopod.org/adaures/castopod/commit/f727276f820a8ef2c47947f40a37a4a157b509ef)), + closes [#323](https://code.castopod.org/adaures/castopod/issues/323) +- **websub:** add missing misc helper import + ([855aacc](https://code.castopod.org/adaures/castopod/commit/855aacce0bf3841a876cd593e668e116149080aa)) + +## [1.3.2](https://code.castopod.org/adaures/castopod/compare/v1.3.1...v1.3.2) (2023-04-14) + +### Bug Fixes + +- remove path key when getting default avatar path + ([c5a1359](https://code.castopod.org/adaures/castopod/commit/c5a1359218d61c0f78006f2bd5785e317f32bade)) +- **s3:** serve files using media base url to allow for CDN setup + ([502f53c](https://code.castopod.org/adaures/castopod/commit/502f53c9701da3b8da2caef1eb54df25b7d2d86a)) + +## [1.3.1](https://code.castopod.org/adaures/castopod/compare/v1.3.0...v1.3.1) (2023-04-13) + +### Bug Fixes + +- **s3:** add proxy to serve images from s3 to client + ([a76724a](https://code.castopod.org/adaures/castopod/commit/a76724a8cfee700f6874f86b35616d61facc664e)), + closes [#321](https://code.castopod.org/adaures/castopod/issues/321) + +# [1.3.0](https://code.castopod.org/adaures/castopod/compare/v1.2.4...v1.3.0) (2023-04-03) + +### Bug Fixes + +- delete files using file_manager when deleting episode and podcast + ([41d8efe](https://code.castopod.org/adaures/castopod/commit/41d8efe6e71566eba44bfdfd00d1708ac4338366)) + +### Features + +- **media:** set media storage directory as configurable + ([7e1a470](https://code.castopod.org/adaures/castopod/commit/7e1a470ba42172eb4c3864ab3652e9f8b55d1ba8)) + +## [1.2.4](https://code.castopod.org/adaures/castopod/compare/v1.2.3...v1.2.4) (2023-03-23) + +### Bug Fixes + +- allow images to have .jpeg extension consistently + ([ae5e12b](https://code.castopod.org/adaures/castopod/commit/ae5e12be3b15fe50cb2311abcbbc19ac23b592f6)) +- **s3:** delete persons image sizes from bucket + add keyPrefix to config + ([208c271](https://code.castopod.org/adaures/castopod/commit/208c2715f900371987c3b75a749fe937a3db1991)) +- **s3:** do not create bucket if not exists, check if healthy instead + ([da7076f](https://code.castopod.org/adaures/castopod/commit/da7076fc2d49d07708d5adaa99733487b7f52e20)) + +### Reverts + +- **homepage:** remove redirect to install if database is not setup + ([d4954e0](https://code.castopod.org/adaures/castopod/commit/d4954e026d5e0d48c5f15ed69d1ce71abb34d1a1)) + +## [1.2.3](https://code.castopod.org/adaures/castopod/compare/v1.2.2...v1.2.3) (2023-03-18) + +### Bug Fixes + +- **notifications:** set mark-all-as-read parameter to be podcast_id instead of + actor_id + ([2748f23](https://code.castopod.org/adaures/castopod/commit/2748f2313797e50d8a2a7b87df09c0bc6e64360a)) + +## [1.2.2](https://code.castopod.org/adaures/castopod/compare/v1.2.1...v1.2.2) (2023-03-18) + +### Bug Fixes + +- **migration:** change old media file_key to file_path + ([a414142](https://code.castopod.org/adaures/castopod/commit/a4141421aa1d6e89742b390b042382f729f965a9)), + closes [#314](https://code.castopod.org/adaures/castopod/issues/314) + +## [1.2.1](https://code.castopod.org/adaures/castopod/compare/v1.2.0...v1.2.1) (2023-03-17) + +### Bug Fixes + +- change app.mediaBaseURL to media.baseURL in install, docker entrypoints and + docs + ([b3c6e05](https://code.castopod.org/adaures/castopod/commit/b3c6e05e6fcd8a518eeedeefde28b61f879ba71d)) + +# [1.2.0](https://code.castopod.org/adaures/castopod/compare/v1.1.2...v1.2.0) (2023-03-17) + +### Bug Fixes + +- **analytics:** check the x_forwarded_for client header + ([1111177](https://code.castopod.org/adaures/castopod/commit/1111177eb7fea4eba6d119b17acdf3bf416492ef)) +- **auth:** update podcast editors' permissions + ([a9b6308](https://code.castopod.org/adaures/castopod/commit/a9b630884bc318499ea7f03862d5752dd5f178e1)) +- **contributors:** add dash to prevent deleting permissions from other podcast + ([5d2a2d4](https://code.castopod.org/adaures/castopod/commit/5d2a2d49c489cd98f9c9ecbca35fd5d21a9cadfb)), + closes [#310](https://code.castopod.org/adaures/castopod/issues/310) +- display bandwidth limit on dashboard when set in .env + ([a2a87ab](https://code.castopod.org/adaures/castopod/commit/a2a87abf7caea3c87bcf2d0988610cc07782de9e)) +- **docker:** update nginx configuration + ([8884598](https://code.castopod.org/adaures/castopod/commit/8884598a56d0e2550776ef4cee5e53558c20e009)) +- **platforms:** update 'submit_url' for Antennapod + ([9fc49a7](https://code.castopod.org/adaures/castopod/commit/9fc49a7430406f50e68318c5fd7c577ae1ebd9df)) + +### Features + +- add downloads count to episode list + ([b63c1dc](https://code.castopod.org/adaures/castopod/commit/b63c1dc9b1ed41626b99ba852a9a00ed417059ba)) +- add health route to check if db, cache and file manager are ok + ([1dde11f](https://code.castopod.org/adaures/castopod/commit/1dde11f8e42b66684a956068f5347e9289f4918b)) +- **media:** add s3 to manage media files + ([d93fc98](https://code.castopod.org/adaures/castopod/commit/d93fc98469ffe93913b65e539dec396891708c70)) + +### Reverts + +- **install:** reset condition to look for instance owner before continuing + install + ([fc009f3](https://code.castopod.org/adaures/castopod/commit/fc009f3d0058028bbbb6418603cf820c0f7cea80)) + +## [1.1.2](https://code.castopod.org/adaures/castopod/compare/v1.1.1...v1.1.2) (2022-12-14) + +### Bug Fixes + +- **analytics:** set EpisodeAudioController to init user session data + ([77ccb30](https://code.castopod.org/adaures/castopod/commit/77ccb306009eb093147c56789535e754f3d85570)) + +## [1.1.1](https://code.castopod.org/adaures/castopod/compare/v1.1.0...v1.1.1) (2022-12-13) + +### Bug Fixes + +- **op3:** remove scheme when wraping audio URI + ([0ad22e4](https://code.castopod.org/adaures/castopod/commit/0ad22e49bc488e96df5a41495f5b242559b64a45)) +- **rss:** add file extension to enclosure url + ([964cbba](https://code.castopod.org/adaures/castopod/commit/964cbba54f16556408bf8280c544a52e6be5c9fc)) + +# [1.1.0](https://code.castopod.org/adaures/castopod/compare/v1.0.5...v1.1.0) (2022-12-09) + +### Bug Fixes + +- **notifications:** remove cache inconsistencies when marking notification as + read + ([46d7054](https://code.castopod.org/adaures/castopod/commit/46d70541d313c836ab0c078ba6121fe5fe956e62)) +- **notifications:** retrieve activity from database instead of getting cache + ([7fbbd08](https://code.castopod.org/adaures/castopod/commit/7fbbd08da6a37d08608900ad318e72815fe4b0c4)) +- **podcast:soundbite:** rename start time attribute to follow spec + ([689831c](https://code.castopod.org/adaures/castopod/commit/689831c26c756d454de432900d23bc09a37f890b)) + +### Features + +- **analytics:** add OP3 analytics service option + update episode audio url + ([16527ed](https://code.castopod.org/adaures/castopod/commit/16527ed529265f2925e205856c684e34175a8933)) + +## [1.0.5](https://code.castopod.org/adaures/castopod/compare/v1.0.4...v1.0.5) (2022-11-25) + +### Bug Fixes + +- **router:** revert to CI4 v4.2.7 to include all routes + ([c13cfa0](https://code.castopod.org/adaures/castopod/commit/c13cfa0ea0679751521ca4157b953043ecc7974a)) + +## [1.0.4](https://code.castopod.org/adaures/castopod/compare/v1.0.3...v1.0.4) (2022-11-21) + +### Bug Fixes + +- update actorUsername regex to get url_to actor + ([1d6b177](https://code.castopod.org/adaures/castopod/commit/1d6b177a55111ede01fba1c08499036d474533bc)) + +## [1.0.3](https://code.castopod.org/adaures/castopod/compare/v1.0.2...v1.0.3) (2022-11-17) + +### Bug Fixes + +- **dashboard-ui:** fill the blank gaps between cards on smaller screen sizes + ([00836cc](https://code.castopod.org/adaures/castopod/commit/00836cc368c75ae2e23fa5dc4a53a5bb6eb2ce24)) + +## [1.0.2](https://code.castopod.org/adaures/castopod/compare/v1.0.1...v1.0.2) (2022-11-04) + +### Bug Fixes + +- **auth:** disallow registration by default + ([379b9be](https://code.castopod.org/adaures/castopod/commit/379b9be2b99574fe4af4009b01128dba2c75f037)) +- **contributors:** add prefix to podcast group to delete contributor + ([9f785db](https://code.castopod.org/adaures/castopod/commit/9f785db7ba674638a6f456aa3626f3f8100911f1)) +- extract podcast ids from user groups using a regex + ([e26215a](https://code.castopod.org/adaures/castopod/commit/e26215a11fc23aa0ad5ccff8ee97d6c6e8a09c1a)) +- **notifications:** add manage-notifications permission to podcast + ([ed7c247](https://code.castopod.org/adaures/castopod/commit/ed7c247bcbbb450e5ff96418930d3b37ce912cc4)) +- **platforms:** convert special characters to htmlentities to validate url + ([82310a2](https://code.castopod.org/adaures/castopod/commit/82310a2e0b426e84501090bdd9c0cf592d1c0d53)) + +## [1.0.1](https://code.castopod.org/adaures/castopod/compare/v1.0.0...v1.0.1) (2022-11-01) + +### Bug Fixes + +- **platforms:** trim platform url before validation and storage + ([259fe5f](https://code.castopod.org/adaures/castopod/commit/259fe5f697a833e268cde88e959bc19bd662edf6)) + +# 1.0.0 (2022-10-20) + +### Bug Fixes + +- **a11y:** replace active tab color to contrast with background on podcast and + episode pages + ([f3785e1](https://code.castopod.org/adaures/castopod/commit/f3785e140147d085a2fb6a62ded87cdfe360f442)) +- **activity-pub:** cache issues when navigating to activity stream urls + ([7bcbfb3](https://code.castopod.org/adaures/castopod/commit/7bcbfb32f7cca08d111be46c7f1640e372d4a4b0)) +- **activity-pub:** get database records using new model instances + ([92536dd](https://code.castopod.org/adaures/castopod/commit/92536ddb3812214a9c5682b92e547e5c1998a5d7)) +- **activitypub:** add conditions for possibly missing actor properties + add + user-agent to requests + ([8fbf948](https://code.castopod.org/adaures/castopod/commit/8fbf948fbba22ffd33966a1b2ccd42e8f7c1f8a2)) +- **activitypub:** add target actor id to like / announce activities to send + directly to note's actor + ([962dd30](https://code.castopod.org/adaures/castopod/commit/962dd305f5d3f6eadc68f400e0e8f953827fe20d)) +- **activitypub:** add target_actor_id for create activity to broadcast post + reply + ([0128a21](https://code.castopod.org/adaures/castopod/commit/0128a21ec55dcc0a2fbf4081dadb4c4737735ba1)) +- **activitypub:** allow cors on get requests for routes exposing acitivitypub + objects + ([2f24809](https://code.castopod.org/adaures/castopod/commit/2f2480998f9abb34f02ab186c65d462a74b4e640)) +- **activitypub:** set created_by to null for reblog if no user + update episode + oembed data + ([209dfbd](https://code.castopod.org/adaures/castopod/commit/209dfbd134e1a2cc02e7c24c158d786fa4dda61d)) +- add admin-audio-player to vite config to have admin player show up + ([93cb9b2](https://code.castopod.org/adaures/castopod/commit/93cb9b24701c09b92820204a67c1fc1b3c044708)) - add application/octet-stream mimetype to mp3 and m4a extensions to prevent ext_in error - ([339bef8](https://code.podlibre.org/podlibre/castopod-host/commit/339bef878e54983d86e91e6ff7a931a843d321b3)), - closes [#145](https://code.podlibre.org/podlibre/castopod-host/issues/145) - -# [1.0.0-alpha.79](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.78...v1.0.0-alpha.79) (2021-12-20) - -### Bug Fixes - -- **import:** set episode and season numbers to null when not present in item - tag - ([3211398](https://code.podlibre.org/podlibre/castopod-host/commit/3211398c78b1b28b76a46427ee07874bbf84a85d)) - -# [1.0.0-alpha.78](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.77...v1.0.0-alpha.78) (2021-12-15) - -### Bug Fixes - + ([339bef8](https://code.castopod.org/adaures/castopod/commit/339bef878e54983d86e91e6ff7a931a843d321b3)), + closes [#145](https://code.castopod.org/adaures/castopod/issues/145) +- add category_label component to include parent category in about podcast page + ([74e7d68](https://code.castopod.org/adaures/castopod/commit/74e7d68ac834885c4b89ee6e7d60db2157165799)) +- add explicit int conversion when formatting episode duration + ([1253096](https://code.castopod.org/adaures/castopod/commit/1253096197a0d30692bdafa7152f250cd9a71acf)) +- add head request to analytics_hit route + ([f0a2f0b](https://code.castopod.org/adaures/castopod/commit/f0a2f0bea491ca91976b351bb79837e95c9d094b)) +- add href to castopod website on login page + ([cc54257](https://code.castopod.org/adaures/castopod/commit/cc5425735184ad738aa0f38540f18e8971f8f56e)) +- add missing explicit badge for podcasts and episodes + ([cdf9f9d](https://code.castopod.org/adaures/castopod/commit/cdf9f9d53f2597f19455cb65c51da4677bb99327)) +- add open graph size for podcast images to replace the inadequate large format + ([33aae1f](https://code.castopod.org/adaures/castopod/commit/33aae1f7934e4962116e94e477dbf48e24971f5f)) +- add public/media folder to castopod bundle + ([8053d35](https://code.castopod.org/adaures/castopod/commit/8053d3521b481872711dabaaf265d08b9bfbaa87)), + closes [#52](https://code.castopod.org/adaures/castopod/issues/52) +- add translation key for audio-clipper trim labels + ([db191ac](https://code.castopod.org/adaures/castopod/commit/db191ac31bd16bad2a72afdb8b25c685adf86a6e)) +- add underline and semibold font weight for prose links to have them stand out + ([d4d8671](https://code.castopod.org/adaures/castopod/commit/d4d867121c50bded4176a53d7154cf1bb347e306)) +- add where condition to get episode count without deleted episodes + ([7661734](https://code.castopod.org/adaures/castopod/commit/7661734ed296654630f3668132671117519145dd)), + closes [#67](https://code.castopod.org/adaures/castopod/issues/67) +- **admin:** save block and lock switches + ([b66c0af](https://code.castopod.org/adaures/castopod/commit/b66c0afc8fab2e338402a9a4f8105e5f5459e208)) +- **analytics:** redirect to mp3 file even when referer was not set + ([9fc388d](https://code.castopod.org/adaures/castopod/commit/9fc388d154f29c335dedcd624abe8c1751762c07)) +- **analytics:** remove charts empty values + remove useless language cache + ([1678794](https://code.castopod.org/adaures/castopod/commit/16787941539ba4014281a366789ea896a9cd2afc)) +- **analytics:** set duration field to precise decimal as episode's audio file + duration + ([d772685](https://code.castopod.org/adaures/castopod/commit/d77268540569b2be9d91d5e09aefb3ff5ac2b071)) +- **analytics:** set initial value for duration and bandwidth + ([ee50539](https://code.castopod.org/adaures/castopod/commit/ee5053959154b1a2e5fbe4b43162968425206a26)) +- **analytics:** update migrations to set decimal precision for latitude and + longitude + ([714d6b5](https://code.castopod.org/adaures/castopod/commit/714d6b5d4950e52cf1c3170bb59954f98ffd48bd)) +- **analytics:** update service management so that it works with new OPAWG slug + values + ([7fe9d42](https://code.castopod.org/adaures/castopod/commit/7fe9d42500ade2c6fa3ff4365b4affc475af0e51)) +- **audio-clipper:** add mouse position offset when stretching clip to prevent + content from jumping + ([602654b](https://code.castopod.org/adaures/castopod/commit/602654b99b33ee8c29da080058a0aaea976cd484)) +- **audio-clipper:** show audio playing progress + put waveform behind audio + clipper + ([01a09dc](https://code.castopod.org/adaures/castopod/commit/01a09dc447b81c5412ceb45d6706a867939fd4dd)) +- **avatar:** use default avatar when no avatar url has been set + ([9d23c7e](https://code.castopod.org/adaures/castopod/commit/9d23c7e7e142c6cf1a1418e37e41d711064593c4)), + closes [#111](https://code.castopod.org/adaures/castopod/issues/111) +- **bundle:** include modules and themes when copying files with rsync + ([cd5bb88](https://code.castopod.org/adaures/castopod/commit/cd5bb8835c6e259408a8c13a2196a347e161da83)) +- **bundle:** update vite input files path + add `set -e` in bash scripts to + fail if command fails + ([0ee53c7](https://code.castopod.org/adaures/castopod/commit/0ee53c71ffadb8a6ddb1febd9f912bc99f5f7a0b)) +- **cache:** add locale for podcast and episode pages + clear some persisting + cache in models + ([9cec8a8](https://code.castopod.org/adaures/castopod/commit/9cec8a81ccbb7239402fe6633dbc31979272302a)), + closes [#42](https://code.castopod.org/adaures/castopod/issues/42) + [#61](https://code.castopod.org/adaures/castopod/issues/61) +- **cache:** delete posts and comments pages cache when updating platform links + ([f7c3e5b](https://code.castopod.org/adaures/castopod/commit/f7c3e5bf4ad43389bf8d58d2c4aaf16b81cbce00)), + closes [#169](https://code.castopod.org/adaures/castopod/issues/169) +- **cache:** return a non cached view when connected + ([e2e7358](https://code.castopod.org/adaures/castopod/commit/e2e735815d805a48eed2ea3288d060d0ddb253a3)) +- **cache:** suffix cache names with authenticated for credits, map and pages + ([418a70b](https://code.castopod.org/adaures/castopod/commit/418a70b2a670d8ba0ab6c15fa5faa41f6be55e53)) +- cast actor_id to pass as int to set_interact_as_actor() function + ([56a8e5d](https://code.castopod.org/adaures/castopod/commit/56a8e5d7dd615322aeb007e730801c65d0b02e5c)) +- **category:** remove uncategorized option to enforce users in choosing a + category + ([8c64f25](https://code.castopod.org/adaures/castopod/commit/8c64f25a0e72fec03d25544797d32623b2276fce)) +- change image size requirement hints + ([ea20206](https://code.castopod.org/adaures/castopod/commit/ea20206ee674eb54dd3ea188d2a2e2d41425df65)) +- change message upon cancellation of episode publication + ([9859c74](https://code.castopod.org/adaures/castopod/commit/9859c7434c2a3478ce035f7a4de20f594d63f5b0)) +- check for database connection and podcasts table existence before redirecting + to install + ([eb74e81](https://code.castopod.org/adaures/castopod/commit/eb74e81c3d93581e310b391cd029e62a0d690a8a)) +- check that additional files are valid when creating episode + ([eac5bc8](https://code.castopod.org/adaures/castopod/commit/eac5bc876de125e1fe08d1b89f767a04fc0fbfb6)) +- check that note has a preview_card_id before displaying it + ([acb8b3a](https://code.castopod.org/adaures/castopod/commit/acb8b3a40172ccb184ffe544760601d756692e6c)), + closes [#114](https://code.castopod.org/adaures/castopod/issues/114) +- clear cache when deleting podcast banner + ([99bb40b](https://code.castopod.org/adaures/castopod/commit/99bb40b8bc17b8ee2cd8468a82e46ea280c92cb6)) +- comment all cache clean after page update to prevent analytics cache deletion + ([e6197a4](https://code.castopod.org/adaures/castopod/commit/e6197a4972a3cce3d67dd7972bb54f8720b8e5b7)) +- **comments:** add comment view partials for public pages + ([fcecbe1](https://code.castopod.org/adaures/castopod/commit/fcecbe1c68b0d28d19454fba65caf3ab769fbc75)) +- correct chart data + ([4d3e9c8](https://code.castopod.org/adaures/castopod/commit/4d3e9c8c02cdc882e9fe1c29625695b6f83c820a)) +- correct percona compatibility issue + ([e53f819](https://code.castopod.org/adaures/castopod/commit/e53f819264b2d6902996f11ffcbb7c99295a90ef)) +- correct php-fpm issues + ([1ef55d7](https://code.castopod.org/adaures/castopod/commit/1ef55d7315bb44abe05f02ec8a84b6b6a557a9a0)) +- correct referrer bug + ([ed69b2f](https://code.castopod.org/adaures/castopod/commit/ed69b2f5004ed1cd18bac824c08a0df01f5d2637)) +- correction for servers with low int precision + ([31b7828](https://code.castopod.org/adaures/castopod/commit/31b7828e77519ef43e9bcfcbdf6c21712f97a571)) +- **cors:** add preflight option routes for episode, podcast and status objects + ([a281abf](https://code.castopod.org/adaures/castopod/commit/a281abfda475388a07943c169dab460cc2d4f944)) +- declare typed properties in PHPDoc for php<7.4 + ([14dd44d](https://code.castopod.org/adaures/castopod/commit/14dd44d03d6db0d9ae4198db8e65c92a0e45cb31)), + closes [#23](https://code.castopod.org/adaures/castopod/issues/23) +- define podcast_id and platform_slug as foreign keys in podcasts_plaforms table + ([6e9451a](https://code.castopod.org/adaures/castopod/commit/6e9451a1103b43750fa70ad576de36af25ca29cb)) +- define podcastNamespaceLink value + ([0d744d2](https://code.castopod.org/adaures/castopod/commit/0d744d212df0d070ceea185068eaf2746e1ccd48)) +- **email:** set the correct url in the activation and forgot emails + ([10fc6f1](https://code.castopod.org/adaures/castopod/commit/10fc6f17c6838a58348f32ccfd0cf05f9d3e172c)), + closes [#204](https://code.castopod.org/adaures/castopod/issues/204) +- **embeddable-player:** enable any ancestor when X-Frame-Options is set on + server + ([44a4962](https://code.castopod.org/adaures/castopod/commit/44a4962e0b7e3ed87e9914b4e7792a0d52330ff8)) +- **embed:** open embedded player's links in new tab + ([4aa73d7](https://code.castopod.org/adaures/castopod/commit/4aa73d71e3b8c0a6c3f75f4d1d45c4d693aba64c)) +- **episode-form:** show warning to set `memory_limit`, `upload_max_filesize` & + `post_max_size` + ([3b3c218](https://code.castopod.org/adaures/castopod/commit/3b3c218b9c868e9f12c54d7670e69d84c9ee79c0)), + closes [#5](https://code.castopod.org/adaures/castopod/issues/5) + [#86](https://code.castopod.org/adaures/castopod/issues/86) +- **episode-unpublish:** set consistent posts_counts' increments/decrements for + actors and episodes + ([8acdafd](https://code.castopod.org/adaures/castopod/commit/8acdafd26044e50a4d6ee451bf24ad66003c5bb3)), + closes [#233](https://code.castopod.org/adaures/castopod/issues/233) +- **episodeCount:** add missing brackets to French language file + ([c1b4112](https://code.castopod.org/adaures/castopod/commit/c1b411265ad9b06e95a8b097ecf73445b88dcb45)) +- **episode:** replace guid's empty string value to null + ([441052a](https://code.castopod.org/adaures/castopod/commit/441052af8d99e6e317edefd1e58ad71799357088)) +- **episodes-page:** handle defaultQuery being null when no podcast episodes + ([15183b7](https://code.castopod.org/adaures/castopod/commit/15183b7eab57dac007bcdfa8c3651239de1ae05a)), + closes [#100](https://code.castopod.org/adaures/castopod/issues/100) +- **episodes-table:** set descriptions to be not null + ([6774ec1](https://code.castopod.org/adaures/castopod/commit/6774ec10fa78527be6b7548ca1dc34ad0ada090c)) +- **episodes:** add publication status + set publication date to null when none + has been set + ([d882981](https://code.castopod.org/adaures/castopod/commit/d882981b3a86c81921ce6b07d4cf61fc13983689)), + closes [#70](https://code.castopod.org/adaures/castopod/issues/70) +- escape characters for `min` in format_duration_symbol + ([3b6722a](https://code.castopod.org/adaures/castopod/commit/3b6722a42b9e4330e5235d4ceed41c777159f4dc)) +- escape generated feed tag values and remove new lines from public pages meta + description + ([6238a43](https://code.castopod.org/adaures/castopod/commit/6238a43863210afe8988ad7cf251e6bfc6c8557c)), + closes [#57](https://code.castopod.org/adaures/castopod/issues/57) + [#46](https://code.castopod.org/adaures/castopod/issues/46) +- expire default query cache upon scheduled episode publication + ([b72e7c8](https://code.castopod.org/adaures/castopod/commit/b72e7c8691c887e41107baea0a4d50a39eaf8c8b)), + closes [#81](https://code.castopod.org/adaures/castopod/issues/81) +- explicitly cast seconds to int in iso8601_duration helper function + ([779653f](https://code.castopod.org/adaures/castopod/commit/779653f75b140942f731cbb238bc0667cc461307)) +- **fediverse:** set default castopod avatar url when actor avatar is not + present + ([460f52f](https://code.castopod.org/adaures/castopod/commit/460f52f70e493d619c28632db6c698e88f0ebb5f)) +- **fediverse:** set model instances as non shared to prevent overlapping + ([91128fa](https://code.castopod.org/adaures/castopod/commit/91128fad7a68e1f4e5acacba90b6899288699e61)) +- fix layout bugs in admin and update translation files + ([a834171](https://code.castopod.org/adaures/castopod/commit/a83417180cf61cdfadc5509b0aaa2fdb66592be3)), + closes [#40](https://code.castopod.org/adaures/castopod/issues/40) +- **follow:** add missing helpers to Actor controller + ([ee53a73](https://code.castopod.org/adaures/castopod/commit/ee53a732dc12ebbf5706e14969749a12cfd9d559)) +- **get_browser_language:** return defaultLocale if browser doesn't send user + preferred language + ([9cc2996](https://code.castopod.org/adaures/castopod/commit/9cc299626181048b85b629bbe7f5806a1f5d21ff)) +- handle HEAD requests on podcast_feed route + ([74b2640](https://code.castopod.org/adaures/castopod/commit/74b2640f2a25c4cd6fd8835fc492c2a6893d4950)), + closes [#79](https://code.castopod.org/adaures/castopod/issues/79) +- **home:** remove hardcoded prefix in getAllPodcasts query + ([92d5cc5](https://code.castopod.org/adaures/castopod/commit/92d5cc50a3e533875cd894dccc417918102d4b7f)) +- **housekeeping:** replace the use of GLOB_BRACE with looping over file + extensions + ([42d92d0](https://code.castopod.org/adaures/castopod/commit/42d92d0c8dfe0c567c28f5bfdda129890fa4c2ec)), + closes [#154](https://code.castopod.org/adaures/castopod/issues/154) +- **housekeeping:** set default sizes value + ignore illegal IFD size error to + proceed with script + ([f21ca57](https://code.castopod.org/adaures/castopod/commit/f21ca57603cfa503699b7e09a155e18d876d65fe)) +- **housekeeping:** use EpisodeModel's builder to reset comments count + ([65e9c0b](https://code.castopod.org/adaures/castopod/commit/65e9c0b05ea4992884149cb4a4b071bf31a20a1a)) +- **htaccess:** add ? after index.php in RewriteRule + ([d9d139e](https://code.castopod.org/adaures/castopod/commit/d9d139eefa03c28d1a064b3b32c9036193497e57)), + closes [#152](https://code.castopod.org/adaures/castopod/issues/152) +- **http-signature:** update SIGNATURE_PATTERN allowing signature keys to be + sent in any order + ([b7f285e](https://code.castopod.org/adaures/castopod/commit/b7f285e4e24247fedb94f030356fa6f291f525cc)) +- **images:** set default mimetype if none is specified when getting size info + ([6e4acc6](https://code.castopod.org/adaures/castopod/commit/6e4acc64ad256178cee7905402b48bafcd49f84c)) +- **import-with-escaped-characters:** remove \CodeIgniter\HTTP\URI in + download_file, closes + [#103](https://code.castopod.org/adaures/castopod/issues/103) + ([35b5be0](https://code.castopod.org/adaures/castopod/commit/35b5be095ff54d27acec1610a846ec0cdbdf1d65)) - **import:** add extension when downloading file without + truncate slug if too long - ([c5f18bb](https://code.podlibre.org/podlibre/castopod-host/commit/c5f18bb6dc08a758ff735454bbe9cfa45a68c09b)) - -# [1.0.0-alpha.77](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.76...v1.0.0-alpha.77) (2021-11-23) - -### Bug Fixes - -- **cors:** add preflight option routes for episode, podcast and status objects - ([a281abf](https://code.podlibre.org/podlibre/castopod-host/commit/a281abfda475388a07943c169dab460cc2d4f944)) + ([c5f18bb](https://code.castopod.org/adaures/castopod/commit/c5f18bb6dc08a758ff735454bbe9cfa45a68c09b)) +- **import:** add validation for handle field to prevent + Router.invalidParameterType error + ([5bf7200](https://code.castopod.org/adaures/castopod/commit/5bf7200fb390f2447b29f24b495f24483cf7b205)), + closes [#119](https://code.castopod.org/adaures/castopod/issues/119) +- **import:** cast description's SimpleXMLElement to string + ([02d17be](https://code.castopod.org/adaures/castopod/commit/02d17be4ffe229fc6657207d31eba0543b5f1a4c)) +- **import:** remove query string from files url + ([109c4aa](https://code.castopod.org/adaures/castopod/commit/109c4aa1afb72dd8b99c0302d74a7fef5a38638e)) +- **import:** save media files during podcast import + set missing media fields + ([a9989d8](https://code.castopod.org/adaures/castopod/commit/a9989d841a634f8cf6c04df25f40bb1e7d4fcdcc)) +- **import:** set default episode type if not set + ([d7250ab](https://code.castopod.org/adaures/castopod/commit/d7250ab03f9b032830c575ad58b51c8d60b7a49a)) +- **import:** set episode and season numbers to null when not present in item + tag + ([3211398](https://code.castopod.org/adaures/castopod/commit/3211398c78b1b28b76a46427ee07874bbf84a85d)) +- **import:** use tag when no is present + ([20e607a](https://code.castopod.org/adaures/castopod/commit/20e607afb755bc75056041738fa7cbf6723d754c)) +- include missing variables on public ui's episode page and remote_actions + ([193b373](https://code.castopod.org/adaures/castopod/commit/193b373bc94a5270acae99b637aa84b6cb2dedfe)) +- **input-component:** unset required attribute to prevent rendering it when + false + ([db9ac13](https://code.castopod.org/adaures/castopod/commit/db9ac13860bce58235a5da275910bea605a00626)) +- **install:** add password validation when creating super admin + ([5a2ca0c](https://code.castopod.org/adaures/castopod/commit/5a2ca0cc4ae85cc15960201c86f131cb822f714f)) +- **install:** redirect manually to install wizard on first visit + ([2ceaaca](https://code.castopod.org/adaures/castopod/commit/2ceaaca44f1b82fc64d961e2fb4f4aaeade7e736)) +- **install:** redirect to host_url install route on instanceConfig validation + error + ([99250b1](https://code.castopod.org/adaures/castopod/commit/99250b1868657c249a447399c7ebc69e00d43d1a)) +- **install:** redirect to input baseUrl after instance config + ([2426af7](https://code.castopod.org/adaures/castopod/commit/2426af7de8c9d426aaf534ff17b67f71c2e9f374)), + closes [#53](https://code.castopod.org/adaures/castopod/issues/53) +- **install:** set message block on forms to show error messages + ([3a0a20d](https://code.castopod.org/adaures/castopod/commit/3a0a20d59cdae7f166325efb750eaa6e9800ba6e)), + closes [#157](https://code.castopod.org/adaures/castopod/issues/157) +- **interact-as:** set actor_id instead of podcast id upon login event + ([5dfade7](https://code.castopod.org/adaures/castopod/commit/5dfade7cf37f339c56d2e577c679b88a1b1d9336)), + closes [#104](https://code.castopod.org/adaures/castopod/issues/104) +- **json-ld:** add missing properties to PodcastSeries object + ([e97266c](https://code.castopod.org/adaures/castopod/commit/e97266c5d4883a10f68b3685ecc0d1942f54d658)) +- keep subtitle line breaks when parsing srt file to json + ([cfb3da6](https://code.castopod.org/adaures/castopod/commit/cfb3da6592f2de23cb1a7ac420f19fc77fa338aa)) +- **layouts:** replace holy-grail layout with tailwind config + widen public + podcast layout + ([be5a287](https://code.castopod.org/adaures/castopod/commit/be5a28787fdb180b64d9bf570120eff7072ab9aa)) +- **map:** update episode markers query to discard unpublished episodes + ([b3caac4](https://code.castopod.org/adaures/castopod/commit/b3caac45b12a23e4289d00133d2ad7915d084c44)) +- **markdown-editor:** remove unnecessary buttons for podcast and episode + editors + add extensions + ([9c4f60e](https://code.castopod.org/adaures/castopod/commit/9c4f60e00bcbd4f784f12d2a6fed357ad402ee2e)) +- **md-editor:** build new markdown editor with lit + + github/markdown-toolbar-element + ([9ec1cb9](https://code.castopod.org/adaures/castopod/commit/9ec1cb93da6f41124c48b8cf14ee6942e865bede)), + closes [#93](https://code.castopod.org/adaures/castopod/issues/93) + [#94](https://code.castopod.org/adaures/castopod/issues/94) + [#120](https://code.castopod.org/adaures/castopod/issues/120) +- **migrations:** ignore invalid utf8 chars for media files metadata + update + transcript parser + ([45e8f99](https://code.castopod.org/adaures/castopod/commit/45e8f99e753cc02ec105e6f4d7fe026a205724f8)) +- minor corrections + ([13be386](https://code.castopod.org/adaures/castopod/commit/13be386842e94d9def1f7de4720931d8f6935171)) +- move analytics to helper + ([d311917](https://code.castopod.org/adaures/castopod/commit/d31191732e41aa106234b5ebe6e54ee02f0ce603)) +- move html escaping on credits page + ([fbffdbd](https://code.castopod.org/adaures/castopod/commit/fbffdbde78544c83138ee6234c62d43056f407b6)) +- **multiselect:** add missing class names in choices options for purge to work + properly + ([719538d](https://code.castopod.org/adaures/castopod/commit/719538d0ccb28af3c3c5e1a4b6468d4b772fe819)) +- **notifications:** add trigger after activities update + update insert trigger + ([e5d16e8](https://code.castopod.org/adaures/castopod/commit/e5d16e87119021fa5a43470d67ddfe5128e57f74)) +- **notifications:** notify actors after activities insert / update using model + callback methods + ([e08555a](https://code.castopod.org/adaures/castopod/commit/e08555a4e9a6c15eeba18273c63403f82eddae35)) +- **open-graph:** replace non existant episode description to podcast + description in podcast page + ([b02584e](https://code.castopod.org/adaures/castopod/commit/b02584ee609af1ad1b5680cc28208d113eb0410b)) +- overwrite common lang function to escape returned string + ([4c490c1](https://code.castopod.org/adaures/castopod/commit/4c490c15bb6642ad0b2aaddf08d8af25de99b4b0)), + closes [#196](https://code.castopod.org/adaures/castopod/issues/196) + [#198](https://code.castopod.org/adaures/castopod/issues/198) +- overwrite getActorById to return app's Actor entity + ([f2bc2f7](https://code.castopod.org/adaures/castopod/commit/f2bc2f7e01aa166faa627df6fe4d5ed4887c16e5)) +- **package.json:** update destination of postcss generation scripts + ([21413f8](https://code.castopod.org/adaures/castopod/commit/21413f8af3b8a0ac01d8c6f15bcd7a63e524e964)) +- **pages:** add locale to page cache + ([8f999ce](https://code.castopod.org/adaures/castopod/commit/8f999ce2f7ee1416c30cf58c84f67b3d11b3f142)) +- **partner:** set correct image URL + ([61554be](https://code.castopod.org/adaures/castopod/commit/61554be12a64d59ab99fab810b1b05632b408f3a)) +- pass timezone to relative time component to show the localized time in the UI + ([b9db936](https://code.castopod.org/adaures/castopod/commit/b9db936461d4cb914958bb3256bb910bbd7ba815)) +- **persons:** prevent overflow of persons list by adding horizontal scroll + ([9e8995d](https://code.castopod.org/adaures/castopod/commit/9e8995dc6e039032cc65f87895cf770f99e8b244)) +- **persons:** set person picture as optional for better ux + ([7fdea63](https://code.castopod.org/adaures/castopod/commit/7fdea63de7e572810082c84fff3013af580df58b)), + closes [#125](https://code.castopod.org/adaures/castopod/issues/125) +- **platforms:** display platform link only when visible is toggled on + ([6e503c8](https://code.castopod.org/adaures/castopod/commit/6e503c8d6182987e48892370623183f871bbd1c1)), + closes [#39](https://code.castopod.org/adaures/castopod/issues/39) +- **player-styling:** revert vite to 2.8 to reference the player css + ([e07d3af](https://code.castopod.org/adaures/castopod/commit/e07d3afea9af85b8361227e000fb64b502781668)) +- **podcast-activity:** check if transcript and chapters are set before + including them in audio + ([5855a25](https://code.castopod.org/adaures/castopod/commit/5855a250936f91641efef77650890a18d8e9917f)) - **podcast-import:** move guid attribute declaration for Episode entity to include slug data - ([5d02ae3](https://code.podlibre.org/podlibre/castopod-host/commit/5d02ae39908a9d743627135b372bf981134c4328)) - -# [1.0.0-alpha.76](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.75...v1.0.0-alpha.76) (2021-10-26) - -### Bug Fixes - + ([5d02ae3](https://code.castopod.org/adaures/castopod/commit/5d02ae39908a9d743627135b372bf981134c4328)) +- **podcast:** use markdown description value for editor + set prose class to + about description + ([f304d97](https://code.castopod.org/adaures/castopod/commit/f304d97b14e0ef383509cb3bba50beb55bf701ba)), + closes [#156](https://code.castopod.org/adaures/castopod/issues/156) +- prefill description footer input when creating a new episode + ([9ea5ca3](https://code.castopod.org/adaures/castopod/commit/9ea5ca31697c70d176294f8aea37bd57d471fcf7)) +- **premium-podcasts:** display unlock button in embed when premium episode + ([ca109ba](https://code.castopod.org/adaures/castopod/commit/ca109ba3a8a08e661fd2484454b1983c3418f15d)) +- **premium-podcasts:** remove cache in unlock form + redirect to podcast if + podcast is not premium + ([242352c](https://code.castopod.org/adaures/castopod/commit/242352c4d9cd936de14e8e8a5d78ebf1287b1f95)) +- **premium-podcasts:** return different cached page when podcast is unlocked + ([b1303c5](https://code.castopod.org/adaures/castopod/commit/b1303c525517498b0edfb9885ff36e08c72628b5)) +- **pwa:** add scope to webmanifests to allow installing an app per podcast + ([74c683e](https://code.castopod.org/adaures/castopod/commit/74c683eb44398a84443ec17903c3e002bb5ea9b9)) +- **pwa:** set app display as standalone in the webmanifests + ([7aa37d2](https://code.castopod.org/adaures/castopod/commit/7aa37d24ac13a1ee160c01a56b43621d7efcfbbc)) +- re-order graph values + ([35f633b](https://code.castopod.org/adaures/castopod/commit/35f633b4c71c087d1ddc9bba9e9bbe18de09204f)) +- redirect to non cached views when authenticated in public views + ([482b47b](https://code.castopod.org/adaures/castopod/commit/482b47ba6bdab7f27fc5704a559567228e07cd14)) +- **release:** add missing version number to castopod-host package + ([8f3e9d9](https://code.castopod.org/adaures/castopod/commit/8f3e9d90c14545d3f84d4469b26a53db4554b4dc)) +- remove cache from remote follow form to display error messages + ([90e4443](https://code.castopod.org/adaures/castopod/commit/90e44437bdf37d8024ef609b2f7336dbdfc3b974)) +- remove defer from js script declaration as it is a module + ([18ae557](https://code.castopod.org/adaures/castopod/commit/18ae557e97f1cef775cd1e75fb1fedee7f1c0cc9)) +- remove fixed size from podcast sidebar + rearrange account info + space out + import radio inputs + ([776eec6](https://code.castopod.org/adaures/castopod/commit/776eec6f0d533d6c92ebec16f7a9dbfcde1f41f4)) +- remove heavy image cover data from audio file metadata + ([f74403b](https://code.castopod.org/adaures/castopod/commit/f74403bd7a5089b760603abe36264e7615be0e78)) +- remove required for other_categories field and add podcast_id to latest + podcasts query + ([5417be0](https://code.castopod.org/adaures/castopod/commit/5417be0049288489a19c7b575aa77bd1e2bc0243)) +- remove required property to persons picture + ([c546be3](https://code.castopod.org/adaures/castopod/commit/c546be385b243014243ae93356006cd126d2f00d)), + closes [#125](https://code.castopod.org/adaures/castopod/issues/125) +- remove value escaping for form inputs and textareas + ([bc6dea2](https://code.castopod.org/adaures/castopod/commit/bc6dea2f8ad1cf0aee0eaa93151332fbac7fb771)) +- rename field status to task_status to get scheduled activities + ([4ff82a5](https://code.castopod.org/adaures/castopod/commit/4ff82a5f0a38dbbc9e272fca7df70ea5a190e334)) +- rename issue_templates labels + ([9f00305](https://code.castopod.org/adaures/castopod/commit/9f00305844e5a168e89d727fe29892b4ad5e48d6)) +- rename MyAccount controller file + ([e109df3](https://code.castopod.org/adaures/castopod/commit/e109df3004a3a98d72de39532e062fff9917f50f)), + closes [#60](https://code.castopod.org/adaures/castopod/issues/60) +- rename podcast name to podcast handle to clarify field usage + ([9dd4c77](https://code.castopod.org/adaures/castopod/commit/9dd4c7741eb1b7cb5fc214ff674697f3aa986df0)), + closes [#126](https://code.castopod.org/adaures/castopod/issues/126) +- reorder fields as composite primary keys for analytics tables + ([9660aa9](https://code.castopod.org/adaures/castopod/commit/9660aa97c8ffd4fe61f3a388d52b9ac5dd8e1d63)) +- replace deletedField with published_at for episodes + ([14d7d07](https://code.castopod.org/adaures/castopod/commit/14d7d078225cdc8980759273a5dc4163d9f84b06)) +- replace getWebEnclosureUrl with getEnclosureWebUrl + ([8122cea](https://code.castopod.org/adaures/castopod/commit/8122ceaf8a70050f14b3078f28b024e7d7cdb9ac)) - replace hardcoded style links with vite service + set default value for remote transcript url - ([3f2e056](https://code.podlibre.org/podlibre/castopod-host/commit/3f2e05608e43d47bbb518a9acfaf56ec3eefafb4)), - closes [#149](https://code.podlibre.org/podlibre/castopod-host/issues/149) - [#150](https://code.podlibre.org/podlibre/castopod-host/issues/150) - -# [1.0.0-alpha.75](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.74...v1.0.0-alpha.75) (2021-10-05) - -### Bug Fixes - + ([3f2e056](https://code.castopod.org/adaures/castopod/commit/3f2e05608e43d47bbb518a9acfaf56ec3eefafb4)), + closes [#149](https://code.castopod.org/adaures/castopod/issues/149) + [#150](https://code.castopod.org/adaures/castopod/issues/150) +- replace website key for webpages in breadcrumb translate file + ([50e32ff](https://code.castopod.org/adaures/castopod/commit/50e32ff75636c1d4c5d945a267e884cb26ad7191)) +- restore default podcast icon on public website + ([342778b](https://code.castopod.org/adaures/castopod/commit/342778bac3c684328d72633961df1a2ebdc1330e)) +- revert to beta.1's codeigniter4 version + ([e831411](https://code.castopod.org/adaures/castopod/commit/e83141127080ccde44987195db46ba97fd6cc2ca)) +- rewrite regenerate image function to use saveSizes method from Image entity + ([3889912](https://code.castopod.org/adaures/castopod/commit/38899124ec27e94a8c798bc2db528f9f785eec20)) +- **router:** check if Accept header is set before getting value + ([10a2ae0](https://code.castopod.org/adaures/castopod/commit/10a2ae02484672d6a0fbc6e7b943519c5ec16cb6)), + closes [#228](https://code.castopod.org/adaures/castopod/issues/228) +- **router:** trim URI slash to match same routes for URIs with and without + trailing slash + ([9e9375f](https://code.castopod.org/adaures/castopod/commit/9e9375f9a2cd6102f827b36ec521f4c86a557c00)) +- **rss-import:** add Castopod user-agent, handle redirects for downloaded + files, add Content namespace + ([214243b](https://code.castopod.org/adaures/castopod/commit/214243b3fec4937e45ef1ceaba1149004cdf3b44)) - **rss:** cast number type values to string in rss_helper - ([7180ae9](https://code.podlibre.org/podlibre/castopod-host/commit/7180ae9ec700930b69c04ed91f8eceea16ad77ce)), - closes [#148](https://code.podlibre.org/podlibre/castopod-host/issues/148) - -# [1.0.0-alpha.74](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.73...v1.0.0-alpha.74) (2021-09-28) - -### Features - -- **platforms:** add missing newpodcastapps.com's platforms - ([92dd370](https://code.podlibre.org/podlibre/castopod-host/commit/92dd370e2f9a464edd26cddcde96d0e16f91548d)) - -# [1.0.0-alpha.73](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.72...v1.0.0-alpha.73) (2021-09-22) - -### Bug Fixes - -- **map:** update episode markers query to discard unpublished episodes - ([b3caac4](https://code.podlibre.org/podlibre/castopod-host/commit/b3caac45b12a23e4289d00133d2ad7915d084c44)) - -# [1.0.0-alpha.72](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.71...v1.0.0-alpha.72) (2021-09-20) - -### Bug Fixes - -- rename field status to task_status to get scheduled activities - ([4ff82a5](https://code.podlibre.org/podlibre/castopod-host/commit/4ff82a5f0a38dbbc9e272fca7df70ea5a190e334)) - -# [1.0.0-alpha.71](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.70...v1.0.0-alpha.71) (2021-09-17) - -### Features - -- **map:** display geolocated episodes on a map page - ([4357cc2](https://code.podlibre.org/podlibre/castopod-host/commit/4357cc25ccc585ce398035c1c25d566b6a9df775)) - -# [1.0.0-alpha.70](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.69...v1.0.0-alpha.70) (2021-08-31) - -### Bug Fixes - -- **partner:** set correct image URL - ([61554be](https://code.podlibre.org/podlibre/castopod-host/commit/61554be12a64d59ab99fab810b1b05632b408f3a)) - -# [1.0.0-alpha.69](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.68...v1.0.0-alpha.69) (2021-08-23) - -### Bug Fixes - -- **import:** cast description's SimpleXMLElement to string - ([02d17be](https://code.podlibre.org/podlibre/castopod-host/commit/02d17be4ffe229fc6657207d31eba0543b5f1a4c)) - -# [1.0.0-alpha.68](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.67...v1.0.0-alpha.68) (2021-08-19) - -### Bug Fixes - -- **analytics:** redirect to mp3 file even when referer was not set - ([9fc388d](https://code.podlibre.org/podlibre/castopod-host/commit/9fc388d154f29c335dedcd624abe8c1751762c07)) - -# [1.0.0-alpha.67](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.66...v1.0.0-alpha.67) (2021-07-24) - -### Features - -- allow cross origin requests on episode comments - ([e12f95a](https://code.podlibre.org/podlibre/castopod-host/commit/e12f95aca13c6d54489a9cfd99d4cd2490fe83ab)) - -# [1.0.0-alpha.66](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.65...v1.0.0-alpha.66) (2021-07-24) - -### Features - -- **rss:** add podcast:comments tag to link to episode comments - ([32e8c7c](https://code.podlibre.org/podlibre/castopod-host/commit/32e8c7c16a61ffe08e2f3bfbdeda556811a0358c)) - -# [1.0.0-alpha.65](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.64...v1.0.0-alpha.65) (2021-07-22) - -### Bug Fixes - + ([7180ae9](https://code.castopod.org/adaures/castopod/commit/7180ae9ec700930b69c04ed91f8eceea16ad77ce)), + closes [#148](https://code.castopod.org/adaures/castopod/issues/148) +- **rss:** do not escape podcast and episode titles in the xml + ([0dd3b7e](https://code.castopod.org/adaures/castopod/commit/0dd3b7e0bf00d5a9eb80c93cba1efcada59ec3c1)), + closes [#138](https://code.castopod.org/adaures/castopod/issues/138) + [#71](https://code.castopod.org/adaures/castopod/issues/71) +- **rss:** remove escaping for publisher and owner name + ([6fc6347](https://code.castopod.org/adaures/castopod/commit/6fc6347846c126618cb7ff50164181650308d0c0)) +- **rss:** round episode durations and soundbites + ([c9fb987](https://code.castopod.org/adaures/castopod/commit/c9fb987fcfbe17069ec68fdbc823777079ce574b)), + closes [#214](https://code.castopod.org/adaures/castopod/issues/214) +- **rss:** set ❬itunes:author❭ tag to owner_name if publisher not specified + ([2271c14](https://code.castopod.org/adaures/castopod/commit/2271c1445b1ded12bc53b5d23b5e59d12b17c71a)), + closes [#96](https://code.castopod.org/adaures/castopod/issues/96) +- **rss:** use originalPath instead of originalMediaPath in Image library + ([b4012b7](https://code.castopod.org/adaures/castopod/commit/b4012b7d2ed6b34b69ad767570dd33f0dc7db920)) +- save transcript and chapters files to podcasts folder + ([63f49c7](https://code.castopod.org/adaures/castopod/commit/63f49c719f672b615c5a8893d3868dffcd332e47)) +- **search-episodes:** add fallback sql query using LIKE for search query with + less than 4 characters + ([e66bf44](https://code.castopod.org/adaures/castopod/commit/e66bf44341175bc5a10fbf7dfa00b351e76136c2)), + closes [#236](https://code.castopod.org/adaures/castopod/issues/236) +- **security:** add csrf filter + prevent xss attacks by escaping user input + ([cd2e1e1](https://code.castopod.org/adaures/castopod/commit/cd2e1e1dc37c53d32d00971c451c4800b8fd6107)) +- set cache expiration to next note publish to show note on publication date + ([0a66de3](https://code.castopod.org/adaures/castopod/commit/0a66de3e6c17d4ac94ee8e13bd00ceaf64b1303e)) +- set episode description footer to null when empty value + ([3a7d97d](https://code.castopod.org/adaures/castopod/commit/3a7d97d660046d80698611311ff3708110d2af82)) +- set episode duration translation to hardcoded english + ([c39efc9](https://code.castopod.org/adaures/castopod/commit/c39efc9489180662edcebd142d4476c0617ea97f)), + closes [#64](https://code.castopod.org/adaures/castopod/issues/64) +- set episode guid upon episode creation + ([ad8b153](https://code.castopod.org/adaures/castopod/commit/ad8b153f2a3b1a3b1751bf63785c4950e1516e6b)), + closes [#48](https://code.castopod.org/adaures/castopod/issues/48) +- set episode numbers during import + remove all custom form_helpers + minor ui + issues + ([99a3b8d](https://code.castopod.org/adaures/castopod/commit/99a3b8d33e00482da50dd62bdaa9215a351a56e4)) +- set interact_as_actor for user upon password reset + ([ad8f5f5](https://code.castopod.org/adaures/castopod/commit/ad8f5f5a0fac7b0b9cc10a0b86200f014aca7553)), + closes [#178](https://code.castopod.org/adaures/castopod/issues/178) +- set localized slug_field key as string in french language + ([17fb29b](https://code.castopod.org/adaures/castopod/commit/17fb29b20993b7deee4e252e0e3a4a2459ee0d98)) +- set location to null when getting empty string + ([71b1b5f](https://code.castopod.org/adaures/castopod/commit/71b1b5f775af475b1dc78328330e277f565e41b6)) +- set storage limit as disk_total_space instead of free space + ([7512e2e](https://code.castopod.org/adaures/castopod/commit/7512e2ed1ff5656cd63a4fc2524296dbb8b4164a)) +- **settings:** add .jpg extension to site-icon file input to display all jpeg + images + ([f611a16](https://code.castopod.org/adaures/castopod/commit/f611a16cd0c1a389e1c5a287eaec9d2a927a4bb6)) +- **socialinteract:** move social interact uri into uri attribute + update + social data upon import + ([12b2200](https://code.castopod.org/adaures/castopod/commit/12b22008a237185cb736fc29352fab22421dad16)) +- sort episodes by published_at with unpublished episodes at the begining + ([1686f84](https://code.castopod.org/adaures/castopod/commit/1686f840d16f2bd3d71d7f222a59b8e6a838fd6e)), + closes [#249](https://code.castopod.org/adaures/castopod/issues/249) +- sort episodic podcasts by season + ([d7b6794](https://code.castopod.org/adaures/castopod/commit/d7b6794f68f9a01fd606a407c6eb4c12d15dee74)) +- **themes:** update themes stylesheet route and remove css extension + ([e4e7e00](https://code.castopod.org/adaures/castopod/commit/e4e7e0005e931967dd6162588f1c5913dbf4603e)) +- **types:** update fake seeders types + fix bugs + ([76a4bf3](https://code.castopod.org/adaures/castopod/commit/76a4bf344160df679db29e236e7df7822970fb60)) +- **ui:** remove empty tooltip when hovering on sponsor button + ([40aa661](https://code.castopod.org/adaures/castopod/commit/40aa661289e1d1517fffcea5d257183bc9c458e4)) +- unpublish episode before deleting it + add validation step before deletion + ([f75bd76](https://code.castopod.org/adaures/castopod/commit/f75bd76458eeb01a2d37912695e33f77d03b7a69)), + closes [#112](https://code.castopod.org/adaures/castopod/issues/112) + [#55](https://code.castopod.org/adaures/castopod/issues/55) +- update .htaccess for shared hosting config + ([2379826](https://code.castopod.org/adaures/castopod/commit/2379826352e2f4b5060910bf9f29268610102f2e)) +- update broken contributor dropdown fields + ([e5b7515](https://code.castopod.org/adaures/castopod/commit/e5b75150234bd7f19e01def93425d3bda7379dd3)) +- update condition in AnalyticsTrait + ([fbc0967](https://code.castopod.org/adaures/castopod/commit/fbc0967caa81630d514ddb1b93b0834ebb4d913b)) +- update condition in home controller to redirect to install page + ([33f1b91](https://code.castopod.org/adaures/castopod/commit/33f1b91d55dd0652c979d50fc85879dbf88a4a42)) - update conditions when checking for empty max_episodes and season_number - ([fbad0b5](https://code.podlibre.org/podlibre/castopod-host/commit/fbad0b59f68c65eba2fdcd5a8d3b312b622e9a45)) - -# [1.0.0-alpha.64](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.63...v1.0.0-alpha.64) (2021-07-12) + ([fbad0b5](https://code.castopod.org/adaures/castopod/commit/fbad0b59f68c65eba2fdcd5a8d3b312b622e9a45)) +- update form_textarea to prevent escaping value + ([78548b5](https://code.castopod.org/adaures/castopod/commit/78548b5cd75ea7d6688d1945ff5449ea4f6bec68)) +- update iso-369 language table seeder + ([0c90db4](https://code.castopod.org/adaures/castopod/commit/0c90db44c40de5af5b0b32b54489bda9424d9ef6)) +- update ivoox podcasting icon + ([f2b69a4](https://code.castopod.org/adaures/castopod/commit/f2b69a47339c887f57883ec612f3d200e512ac1c)) +- update MarkdownEditor component + restyle Button and other components + ([b05d177](https://code.castopod.org/adaures/castopod/commit/b05d177f1b7f44fef043ac5eb41f07133a2cf52d)) +- update purgecss content path for php helper files + ([eb70bb4](https://code.castopod.org/adaures/castopod/commit/eb70bb4f7078ff347aeb8f5dcc7896311d289466)), + closes [#59](https://code.castopod.org/adaures/castopod/issues/59) +- update translations for settings' tasks to include what they should be used + for + ([06b1a8b](https://code.castopod.org/adaures/castopod/commit/06b1a8b29b6ce5d81c5570d250bdac4e0c9ee5ca)) +- use slash instead of backslash to call layout + ([a80adb2](https://code.castopod.org/adaures/castopod/commit/a80adb22958fc0a38374cbce2d950a0042e699eb)) +- use UTC_TIMESTAMP() to get current utc date instead of NOW() in sql queries + ([4e22a0d](https://code.castopod.org/adaures/castopod/commit/4e22a0d5e4b60941d41071f059aac80cbaf38fbf)) +- **users:** remove required roles input when editing user + prevent owner's + roles from being edited + ([1c8af75](https://code.castopod.org/adaures/castopod/commit/1c8af7550ba27d8c8473ae96acd21ad7731fd863)), + closes [#239](https://code.castopod.org/adaures/castopod/issues/239) +- **ux:** allow for empty message upon episode publication and warn user on + submit + ([33d01b8](https://code.castopod.org/adaures/castopod/commit/33d01b8d4fd6ebf24e9f011aa705c456c846956c)), + closes [#129](https://code.castopod.org/adaures/castopod/issues/129) +- **ux:** have podcast dashboard card link to podcast dashboard if only one + podcast in instance + ([7dabee5](https://code.castopod.org/adaures/castopod/commit/7dabee58a187abe92358d962da506a836e29cda3)) +- **ux:** redirect user to install page on database error in home page + ([9017e30](https://code.castopod.org/adaures/castopod/commit/9017e30bf41bed8c2be65091bbc5fb1e63aef87a)) +- validate slug length when submitting episode form + clean permalink edit + prefix + ([b07ac09](https://code.castopod.org/adaures/castopod/commit/b07ac093b2cae646f9a897bc9dfeeaef6eda6561)) +- **video-clips:** check if created video exists before recreating it and + failing + ([dff1208](https://code.castopod.org/adaures/castopod/commit/dff12087251b2b89e195604202094b5ddd9a0936)) +- **video-clips:** clear video clip cache after process has finished + ([3ae6232](https://code.castopod.org/adaures/castopod/commit/3ae62325856f6ff331a5d9ed901b9fa097ca7055)) +- **video-clips:** create unique temporary files for resources to be deleted + after generation + ([7f7c878](https://code.castopod.org/adaures/castopod/commit/7f7c878cb6ecf7b4a967b2af87da82bc6593081e)) +- **video-clips:** set audio codec to aac, fixing audio issue on twitter + ([3c22c68](https://code.castopod.org/adaures/castopod/commit/3c22c68ee81f77bd7fcf7e2739ee6af016407843)) +- **video-clips:** set longer podcast and episode lengths for squared format + ([c030113](https://code.castopod.org/adaures/castopod/commit/c0301134c2048dc29eb2b995e4d5c22c49444100)) +- **video-clips:** tweak portrait parameters to have subtitles display without + overflowing + ([2385b1a](https://code.castopod.org/adaures/castopod/commit/2385b1a2926d1344569836e18cb30adb4c604664)) +- **video-clips:** update condition to check if ffmpeg is installed + ([b57f0b6](https://code.castopod.org/adaures/castopod/commit/b57f0b6eb65dccf22cb4d55f93d18ca36857d7fc)), + closes [#163](https://code.castopod.org/adaures/castopod/issues/163) +- **xml-editor:** escape xml editor's content + restyle form sections to prevent + overflowing + ([588590b](https://code.castopod.org/adaures/castopod/commit/588590bd2c0346e2465ff8f1930580d76a3bf068)) +- **xml-editor:** prettify xml even without root node + ([ca55c24](https://code.castopod.org/adaures/castopod/commit/ca55c248d0562a8529071c1f10be12f40ef50dda)) ### Features - **activitypub:** add Podcast actor and PodcastEpisode object with comments - ([9e1e5d2](https://code.podlibre.org/podlibre/castopod-host/commit/9e1e5d2e862d6a3345d11ca7f96b955c76bfa013)) - -# [1.0.0-alpha.63](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.62...v1.0.0-alpha.63) (2021-07-12) - -### Features - -- build hashed static files to renew browser cache - ([37c54d2](https://code.podlibre.org/podlibre/castopod-host/commit/37c54d247749bdf8f528babd4a78f24d48051063)), - closes [#107](https://code.podlibre.org/podlibre/castopod-host/issues/107) - -# [1.0.0-alpha.62](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.61...v1.0.0-alpha.62) (2021-07-02) - -### Bug Fixes - -- **episode:** replace guid's empty string value to null - ([441052a](https://code.podlibre.org/podlibre/castopod-host/commit/441052af8d99e6e317edefd1e58ad71799357088)) - -# [1.0.0-alpha.61](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.60...v1.0.0-alpha.61) (2021-06-23) - -### Bug Fixes - -- **release:** add missing version number to castopod-host package - ([8f3e9d9](https://code.podlibre.org/podlibre/castopod-host/commit/8f3e9d90c14545d3f84d4469b26a53db4554b4dc)) -- **ux:** allow for empty message upon episode publication and warn user on - submit - ([33d01b8](https://code.podlibre.org/podlibre/castopod-host/commit/33d01b8d4fd6ebf24e9f011aa705c456c846956c)), - closes [#129](https://code.podlibre.org/podlibre/castopod-host/issues/129) - -# [1.0.0-alpha.60](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.59...v1.0.0-alpha.60) (2021-06-21) - -### Features - -- **rss:** add ˂podcast:guid˃ tag for channel - ([1fab10e](https://code.podlibre.org/podlibre/castopod-host/commit/1fab10eb0d63bb7c3edf34ffe691e2aec2c2e43c)) - -# [1.0.0-alpha.59](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.58...v1.0.0-alpha.59) (2021-06-15) - -### Bug Fixes - -- check that additional files are valid when creating episode - ([eac5bc8](https://code.podlibre.org/podlibre/castopod-host/commit/eac5bc876de125e1fe08d1b89f767a04fc0fbfb6)) - -# [1.0.0-alpha.58](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.57...v1.0.0-alpha.58) (2021-06-11) - -### Bug Fixes - -- cast actor_id to pass as int to set_interact_as_actor() function - ([56a8e5d](https://code.podlibre.org/podlibre/castopod-host/commit/56a8e5d7dd615322aeb007e730801c65d0b02e5c)) -- **analytics:** set duration field to precise decimal as episode's audio file - duration - ([d772685](https://code.podlibre.org/podlibre/castopod-host/commit/d77268540569b2be9d91d5e09aefb3ff5ac2b071)) -- **analytics:** update migrations to set decimal precision for latitude and - longitude - ([714d6b5](https://code.podlibre.org/podlibre/castopod-host/commit/714d6b5d4950e52cf1c3170bb59954f98ffd48bd)) -- check for database connection and podcasts table existence before redirecting - to install - ([eb74e81](https://code.podlibre.org/podlibre/castopod-host/commit/eb74e81c3d93581e310b391cd029e62a0d690a8a)) -- save transcript and chapters files to podcasts folder - ([63f49c7](https://code.podlibre.org/podlibre/castopod-host/commit/63f49c719f672b615c5a8893d3868dffcd332e47)) -- set cache expiration to next note publish to show note on publication date - ([0a66de3](https://code.podlibre.org/podlibre/castopod-host/commit/0a66de3e6c17d4ac94ee8e13bd00ceaf64b1303e)) -- set episode description footer to null when empty value - ([3a7d97d](https://code.podlibre.org/podlibre/castopod-host/commit/3a7d97d660046d80698611311ff3708110d2af82)) -- set location to null when getting empty string - ([71b1b5f](https://code.podlibre.org/podlibre/castopod-host/commit/71b1b5f775af475b1dc78328330e277f565e41b6)) -- update condition in home controller to redirect to install page - ([33f1b91](https://code.podlibre.org/podlibre/castopod-host/commit/33f1b91d55dd0652c979d50fc85879dbf88a4a42)) -- **activity-pub:** cache issues when navigating to activity stream urls - ([7bcbfb3](https://code.podlibre.org/podlibre/castopod-host/commit/7bcbfb32f7cca08d111be46c7f1640e372d4a4b0)) -- **activity-pub:** get database records using new model instances - ([92536dd](https://code.podlibre.org/podlibre/castopod-host/commit/92536ddb3812214a9c5682b92e547e5c1998a5d7)) -- **category:** remove uncategorized option to enforce users in choosing a - category - ([8c64f25](https://code.podlibre.org/podlibre/castopod-host/commit/8c64f25a0e72fec03d25544797d32623b2276fce)) -- **install:** redirect manually to install wizard on first visit - ([2ceaaca](https://code.podlibre.org/podlibre/castopod-host/commit/2ceaaca44f1b82fc64d961e2fb4f4aaeade7e736)) -- **types:** update fake seeders types + fix bugs - ([76a4bf3](https://code.podlibre.org/podlibre/castopod-host/commit/76a4bf344160df679db29e236e7df7822970fb60)) -- update broken contributor dropdown fields - ([e5b7515](https://code.podlibre.org/podlibre/castopod-host/commit/e5b75150234bd7f19e01def93425d3bda7379dd3)) -- **ux:** redirect user to install page on database error in home page - ([9017e30](https://code.podlibre.org/podlibre/castopod-host/commit/9017e30bf41bed8c2be65091bbc5fb1e63aef87a)) -- update condition in AnalyticsTrait - ([fbc0967](https://code.podlibre.org/podlibre/castopod-host/commit/fbc0967caa81630d514ddb1b93b0834ebb4d913b)) - -### Performance Improvements - -- **cache:** use deleteMatching method to prevent forgetting cached elements in - models - ([76afc0c](https://code.podlibre.org/podlibre/castopod-host/commit/76afc0cfa2feb087697bae4bc138e4956873dd62)) - -### Reverts - -- set deprecated config options back in App config - ([433745f](https://code.podlibre.org/podlibre/castopod-host/commit/433745f194c73407999b207090478563283876a5)) - -# [1.0.0-alpha.57](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.56...v1.0.0-alpha.57) (2021-05-12) - -### Bug Fixes - -- **follow:** add missing helpers to Actor controller - ([ee53a73](https://code.podlibre.org/podlibre/castopod-host/commit/ee53a732dc12ebbf5706e14969749a12cfd9d559)) - -# [1.0.0-alpha.56](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.55...v1.0.0-alpha.56) (2021-05-12) - -### Bug Fixes - -- **rss:** use originalPath instead of originalMediaPath in Image library - ([b4012b7](https://code.podlibre.org/podlibre/castopod-host/commit/b4012b7d2ed6b34b69ad767570dd33f0dc7db920)) - -# [1.0.0-alpha.55](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.54...v1.0.0-alpha.55) (2021-05-03) - -### Features - + ([9e1e5d2](https://code.castopod.org/adaures/castopod/commit/9e1e5d2e862d6a3345d11ca7f96b955c76bfa013)) +- add about page in admin with instance info + database update button + ([d0836f3](https://code.castopod.org/adaures/castopod/commit/d0836f3ee360a836f815c59ea755f288501dc517)) +- add alternate rss feed link tag to podcast page head + ([a973c09](https://code.castopod.org/adaures/castopod/commit/a973c097d54a3d0186c4079b9d4d3e81aae38505)), + closes [#35](https://code.castopod.org/adaures/castopod/issues/35) +- add analytics and unknown useragents + ([ec92e65](https://code.castopod.org/adaures/castopod/commit/ec92e65aa42e09b1df04600b52a0c679dfc494bb)) +- add audio-clipper toolbar + add video-clip-previewer + ([0255753](https://code.castopod.org/adaures/castopod/commit/02557539e6eb48fc23ee2ee3b0c75aee3310965b)) +- add audio-clipper webcomponent (wip) + ([21d4251](https://code.castopod.org/adaures/castopod/commit/21d4251b9bcd5acb0f8a1761bc4edc34a3dbc228)) +- add autofocus to input field "Email or username" on login page + ([19caed4](https://code.castopod.org/adaures/castopod/commit/19caed4bce0daab9ccf6ab9645f44b60eb87de88)) +- add basic stats on podcast about page + ([1670558](https://code.castopod.org/adaures/castopod/commit/1670558473dba47219d470ff21d6224db6ab42ba)) +- add breadcrumb in admin area + ([7fb1de2](https://code.castopod.org/adaures/castopod/commit/7fb1de2cf3c97c4cd7afe3bd71bbe66041786ecd)), + closes [#17](https://code.castopod.org/adaures/castopod/issues/17) +- add cache to ActivityPub sql queries + cache activity and note pages + ([2d297f4](https://code.castopod.org/adaures/castopod/commit/2d297f45b3d7ef6e8711875a0b9b908e878115fa)) +- add CDN url + ([972bcbf](https://code.castopod.org/adaures/castopod/commit/972bcbf65ee119b8641ca3c4e5c0e8cf9ca8dd4f)), + closes [#37](https://code.castopod.org/adaures/castopod/issues/37) +- add codemirror to display xml editor for custom rss field + ([f15f262](https://code.castopod.org/adaures/castopod/commit/f15f26240cd5311fa9d07779f364b6639a501dec)) +- add cumulative listening time charts + ([588b4d2](https://code.castopod.org/adaures/castopod/commit/588b4d28da00bc12d02126e23181690f54d81716)) +- add default icons to Alert component + ([0d98001](https://code.castopod.org/adaures/castopod/commit/0d9800123b135e4fa1a2acd14a5e039c12174333)) +- add DropdownMenu component + remove global audio player in admin + ([abb7fba](https://code.castopod.org/adaures/castopod/commit/abb7fbac276d77b7d31a0aeba75d464f3ba3ad46)) +- add episode_numbering() component helper to display episode and season numbers + ([3f4a6bd](https://code.castopod.org/adaures/castopod/commit/3f4a6bd0b9f870f16107a41b102b6bf734868198)) +- add french translation + ([196920d](https://code.castopod.org/adaures/castopod/commit/196920d62f1810b4c35f800d17d7f93627319091)) +- add heading component + update ecs rules to fix views + ([23bdc6f](https://code.castopod.org/adaures/castopod/commit/23bdc6f8e36b7e8dfbe32755a54dea59ad913432)) +- add housekeeping task to run after migrations + ([89dee41](https://code.castopod.org/adaures/castopod/commit/89dee41d583e57251ea9315402a757f03571d7ad)) +- add install wizard form to bootstrap database and create the first superadmin + user + ([cba871c](https://code.castopod.org/adaures/castopod/commit/cba871c5df9f7120c44d9952456ebbd0d220669e)), + closes [#2](https://code.castopod.org/adaures/castopod/issues/2) +- add instructions on production error page to ease Castopod debugging process + ([9eab54e](https://code.castopod.org/adaures/castopod/commit/9eab54e0853ccb8300d9f9b743cd84aefbf06549)), + closes [#224](https://code.castopod.org/adaures/castopod/issues/224) +- add ISO 3166 country codes + ([97cd94b](https://code.castopod.org/adaures/castopod/commit/97cd94b47494b66faf43fbbe0748872da80020a4)) +- add js audio player on podcast, admin and embeddable player pages + fix admon + episodes ux + ([0e14eb4](https://code.castopod.org/adaures/castopod/commit/0e14eb4d3f526b0fd256a6144f3fbfc3fe52a357)), + closes [#131](https://code.castopod.org/adaures/castopod/issues/131) +- add label to sponsor button on podcast page + ([c29c018](https://code.castopod.org/adaures/castopod/commit/c29c018c7a543fc9398b5d7d11f086123e2b33f2)), + closes [#162](https://code.castopod.org/adaures/castopod/issues/162) +- add legalNoticeURL to app config for setting an external url to legal notice + ([711843a](https://code.castopod.org/adaures/castopod/commit/711843a0c81e1e2ec7a015431786df4ef32d5092)) +- add lock podcast according to the Podcastindex podcast-namespace to prevent + unauthozized import + ([72b3012](https://code.castopod.org/adaures/castopod/commit/72b301272e0b70ded3e2b237391909e3f152ad0b)) +- add map analytics, add episodes analytics, clean analytics page layout, + translate countries + ([07eae83](https://code.castopod.org/adaures/castopod/commit/07eae83a00d860e149359fae67d549488403d88b)) +- add media entity and link documents, images and audio files to it + ([6ecf286](https://code.castopod.org/adaures/castopod/commit/6ecf2866cfcde31a0840f15c3340808ce14b44cf)) +- add notifications inbox for actors + ([999999e](https://code.castopod.org/adaures/castopod/commit/999999e3efab7b1aad7568e4fd114dc7bac04f38)), + closes [#215](https://code.castopod.org/adaures/castopod/issues/215) +- add Noto Sans Mono font to use for durations + button to access new video clip + form in list + ([7609bb6](https://code.castopod.org/adaures/castopod/commit/7609bb60330539aa91bfdafbb35c2d585624218a)) +- add npm for js dependencies + move src/ files to root folder + ([cbb83a6](https://code.castopod.org/adaures/castopod/commit/cbb83a6f308ac9357e9fb0cca5edae9d3fee5b48)) +- add Open Graph and Twitter meta tags + ([af970b8](https://code.castopod.org/adaures/castopod/commit/af970b8bac949e4c63047e04aca1b7403a4e8deb)), + closes [#41](https://code.castopod.org/adaures/castopod/issues/41) +- add pages table to store custom instance pages (eg. legal-notice, cookie + policy, etc.) + ([9c224a8](https://code.castopod.org/adaures/castopod/commit/9c224a8ac6dd95f3c6c087a300fc8bac48e8090f)), + closes [#24](https://code.castopod.org/adaures/castopod/issues/24) +- add permanent delete feature for podcasts 🎉 + ([dbb4030](https://code.castopod.org/adaures/castopod/commit/dbb4030da49f9ea1f61759fb7c66d71fc29ea4a1)), + closes [#89](https://code.castopod.org/adaures/castopod/issues/89) +- add platform models + ([a333d29](https://code.castopod.org/adaures/castopod/commit/a333d291966229a909c0851fd8b890ed97c48ceb)) +- add platforms form in podcast settings + ([043f49c](https://code.castopod.org/adaures/castopod/commit/043f49c784bc007ca0fa756ca4ed2d3b08843ad9)) +- add platforms tables + ([ce59344](https://code.castopod.org/adaures/castopod/commit/ce5934419a516c9926dd3fd0ace3c11a95b60722)) +- add podcast banner field for each podcast + refactor images configuration + ([4a8147b](https://code.castopod.org/adaures/castopod/commit/4a8147bfbbd98d9badfc57a0f2a18bdd5812e802)) +- add premium podcasts to manage subscriptions for premium episodes + ([3234500](https://code.castopod.org/adaures/castopod/commit/3234500e2d967438ad140f65da801a543f43775d)), + closes [#193](https://code.castopod.org/adaures/castopod/issues/193) +- add publish feature for podcasts and set draft by default + ([3d363f2](https://code.castopod.org/adaures/castopod/commit/3d363f2efe99836ac05c305a2fa683e342f06561)), + closes [#128](https://code.castopod.org/adaures/castopod/issues/128) + [#220](https://code.castopod.org/adaures/castopod/issues/220) - add remote_url alternative for transcript and chapters files - ([3143c9a](https://code.podlibre.org/podlibre/castopod-host/commit/3143c9ad36e4cf1364205cf2be39c0c96f80fdd2)) - -# [1.0.0-alpha.54](https://code.podlibre.org/podlibre/castopod-host/compare/v1.0.0-alpha.53...v1.0.0-alpha.54) (2021-05-03) - -### Features - + ([3143c9a](https://code.castopod.org/adaures/castopod/commit/3143c9ad36e4cf1364205cf2be39c0c96f80fdd2)) +- add replied to post or comment to reply element + ([d0f9c60](https://code.castopod.org/adaures/castopod/commit/d0f9c6018f1af527099f3e26b5d824710fa11caf)) +- add schema.org json-ld objects to podcasts, episodes, posts and comments pages + ([902f959](https://code.castopod.org/adaures/castopod/commit/902f959b30a10839684f093eb86edebc5d826a0b)) +- add task to housekeeping setting for resetting all instance counts + ([9303e51](https://code.castopod.org/adaures/castopod/commit/9303e51bc50d730a8026f58984e83b840360ee88)) +- add unique listeners analytics + ([3a49258](https://code.castopod.org/adaures/castopod/commit/3a4925816f3268230640525ad7af507aab8eecb9)) +- add update rss feed feature for podcasts to import their latest episodes + ([5eb9dc1](https://code.castopod.org/adaures/castopod/commit/5eb9dc168eb9af04767829b76242c9120f55d46d)), + closes [#183](https://code.castopod.org/adaures/castopod/issues/183) +- add user permissions and basic groups to handle authorizations + ([d58e518](https://code.castopod.org/adaures/castopod/commit/d58e51874a4722921b75b0049117015c2380406e)), + closes [#3](https://code.castopod.org/adaures/castopod/issues/3) + [#18](https://code.castopod.org/adaures/castopod/issues/18) +- add WebSub module for pushing feed updates to open hubs + ([10d3f73](https://code.castopod.org/adaures/castopod/commit/10d3f73786ba141e27a822b2585c4a244ee92c14)) +- **admin:** add instance wide dashboard with storage and bandwidth usage + ([b1a6c02](https://code.castopod.org/adaures/castopod/commit/b1a6c02e56fdc01a7ff69fa7e7dd8ea71380b7ba)), + closes [#216](https://code.castopod.org/adaures/castopod/issues/216) +- **admin:** add search form in podcast episodes list + ([6be5d12](https://code.castopod.org/adaures/castopod/commit/6be5d12877342a7c56e25ea8dd15a975c6ce45ac)), + closes [#26](https://code.castopod.org/adaures/castopod/issues/26) +- **admin:** make header stick on scroll and show title + action buttons using + css only + ([d60498c](https://code.castopod.org/adaures/castopod/commit/d60498c1beb970a14eeb3bbe02d1b1d8116624b0)) +- **admin:** update admin layout for better ux + update brand pine colors + ([d86142e](https://code.castopod.org/adaures/castopod/commit/d86142ebe7cd7582835f180b79fbeaaaba703528)) +- allow cross origin requests on episode comments + ([e12f95a](https://code.castopod.org/adaures/castopod/commit/e12f95aca13c6d54489a9cfd99d4cd2490fe83ab)) +- **analytics-gdpr:** update cached personal data to expire at midnight + ([0188b67](https://code.castopod.org/adaures/castopod/commit/0188b67354a756f0c926edd7b46623ab5b20c12b)) +- **analytics:** add 'other' group to pie charts in order to display more + accurate data + ([73acef9](https://code.castopod.org/adaures/castopod/commit/73acef933ff3485987afc5157de022910876fc12)) +- **analytics:** add charts and data export + ([78625c4](https://code.castopod.org/adaures/castopod/commit/78625c471b4f03a09bd42f72b82217e1f2d01cef)) +- **analytics:** add current date and secret salt to analytics hash for improved + privacy + ([6f2e7c0](https://code.castopod.org/adaures/castopod/commit/6f2e7c009c24830d4f08633bfbde3b75f40bf215)) +- **analytics:** add service name from rss user-agent + ([7202b98](https://code.castopod.org/adaures/castopod/commit/7202b9867bd59aafa8c338a4230fb5e5c55b24c6)) +- **analytics:** add weekday and hour bar charts + ([8ab3132](https://code.castopod.org/adaures/castopod/commit/8ab313296bb4a254ab05e90b17d896039839b784)) +- **api:** add rest api with podcasts read endpoints + ([e64001d](https://code.castopod.org/adaures/castopod/commit/e64001d00604bcf587ec5e9a631282f212df450d)), + closes [#210](https://code.castopod.org/adaures/castopod/issues/210) +- apply colour theme to embed player + ([9548337](https://code.castopod.org/adaures/castopod/commit/9548337a7c49879e8b58c2dfece46e3cfc9517eb)), + closes [#201](https://code.castopod.org/adaures/castopod/issues/201) +- **auth:** add auth.enable2FA config to enable two-factor authentication + ([7213ed2](https://code.castopod.org/adaures/castopod/commit/7213ed290c977ce8723f6d92addadc03913576ee)) +- build hashed static files to renew browser cache + ([37c54d2](https://code.castopod.org/adaures/castopod/commit/37c54d247749bdf8f528babd4a78f24d48051063)), + closes [#107](https://code.castopod.org/adaures/castopod/issues/107) +- **cache:** add podcast and episode pages to cache + clear them after insert or + update + ([da0f047](https://code.castopod.org/adaures/castopod/commit/da0f0472819007e02e5da37399f2377772c618b9)) +- **categories:** create model, entity, migrations and seeds + ([f73b042](https://code.castopod.org/adaures/castopod/commit/f73b042cc091be82abdbbca8992080875d526972)) +- **clips:** setup clip entities and model + save video clip to have it + generated in the background + ([2f6fdf9](https://code.castopod.org/adaures/castopod/commit/2f6fdf9091d52ca49709fc82621ba1c6dd0e817d)) +- **comments:** add comments to episodes + update naming of status to post + ([bb4752c](https://code.castopod.org/adaures/castopod/commit/bb4752c35e086664f5fd75fdc0d56546a1e356f6)) +- **comments:** add like / undo like to comment + add comment page + ([0c187ef](https://code.castopod.org/adaures/castopod/commit/0c187ef7a9278a60bcc6e5ee4d69d948b51e5c54)) +- **components:** add custom view renderer with ComponentRenderer adapted from + bonfire2 + ([a95de8b](https://code.castopod.org/adaures/castopod/commit/a95de8bab010f6b01c598da72191abe97e473687)) +- create optimized & resized images upon upload + ([02e4441](https://code.castopod.org/adaures/castopod/commit/02e4441f98f27e9534e5b9b63279153d14632ccd)), + closes [#6](https://code.castopod.org/adaures/castopod/issues/6) +- **custom-rss:** add custom xml tag injection in rss feed for ❬channel❭ and + ❬item❭ + ([6ecdaad](https://code.castopod.org/adaures/castopod/commit/6ecdaad911d06b7f7a2b7d24710968c7eb9118f6)) +- **datetime-picker:** set material_green theme to flatpickr + ([3ce6541](https://code.castopod.org/adaures/castopod/commit/3ce6541003260677e722a916ad6bc83ef47c4371)) +- **devcontainer:** add devcontainer settings for dev environment + ([69e7266](https://code.castopod.org/adaures/castopod/commit/69e72667365247b63430dee88194e8f0d7c28edc)) +- display castopod version in admin footer + ([9f2574e](https://code.castopod.org/adaures/castopod/commit/9f2574e6fbb61dac4e1a4252dff30017685da5f0)), + closes [#68](https://code.castopod.org/adaures/castopod/issues/68) +- display legal disclaimer and warning on podcast import page + ([2f07992](https://code.castopod.org/adaures/castopod/commit/2f07992e5508b34b91f194eebfac80c51e80e90a)), + closes [#34](https://code.castopod.org/adaures/castopod/issues/34) +- edit + delete podcast and episode + ([ac5f0c7](https://code.castopod.org/adaures/castopod/commit/ac5f0c732806e955c01e05b7867801bc938c6bd5)) +- **embeddable-player:** add embeddable player widget + ([141788f](https://code.castopod.org/adaures/castopod/commit/141788fa089f9dedc8956c64ca515a4a4625f904)) +- enhance admin ui with responsive design and ux improvements + ([2d44b45](https://code.castopod.org/adaures/castopod/commit/2d44b457a02205d2e7da258d7029b8bc5da39533)), + closes [#31](https://code.castopod.org/adaures/castopod/issues/31) + [#9](https://code.castopod.org/adaures/castopod/issues/9) +- enhance ui using javascript in admin area + ([c0e66d5](https://code.castopod.org/adaures/castopod/commit/c0e66d5f7012026e145d106f4d6bd3ba792a1b77)) +- **episode-unpublish:** remove episode comments upon unpublish + ([78acd7f](https://code.castopod.org/adaures/castopod/commit/78acd7f5c057c82507d801c424040296dbaba586)) +- **episode:** add form to allow editing episode's publication date to a past + date + ([d783d16](https://code.castopod.org/adaures/castopod/commit/d783d16eb73d3f896a3dea39a766b4e963e53abf)), + closes [#97](https://code.castopod.org/adaures/castopod/issues/97) +- **episodes:** add create form and view pages for episode + ([f3b2c8b](https://code.castopod.org/adaures/castopod/commit/f3b2c8b84f3d93bef734e34dbe8ed729535e45e9)), + closes [#1](https://code.castopod.org/adaures/castopod/issues/1) +- **episodes:** add migrations, model and entity for episodes table + ([0444821](https://code.castopod.org/adaures/castopod/commit/044482174ede555ce19a2d8c6f48771cc8e7d27b)) +- **episodes:** replace all audio file URL parameters with base64 encoded data + ([e1f65cd](https://code.castopod.org/adaures/castopod/commit/e1f65cd3b53353a30d4ab6eb5312393cf04a1676)) +- **episodes:** replace soft delete with permanent delete + ([eb9ff52](https://code.castopod.org/adaures/castopod/commit/eb9ff522c25af8ceb2ed08614b581757ee791d42)) +- **episodes:** schedule episode with future publication_date by using cache + expiration time + ([4f1e773](https://code.castopod.org/adaures/castopod/commit/4f1e773c0f9e4c2597f6c1b0a4773dfb34b2f203)), + closes [#47](https://code.castopod.org/adaures/castopod/issues/47) +- **fediverse:** implement activitypub protocols + update user interface + ([2f525c0](https://code.castopod.org/adaures/castopod/commit/2f525c0f6e44d320bff16e22c223481923ba683e)), + closes [#69](https://code.castopod.org/adaures/castopod/issues/69) + [#65](https://code.castopod.org/adaures/castopod/issues/65) + [#85](https://code.castopod.org/adaures/castopod/issues/85) + [#51](https://code.castopod.org/adaures/castopod/issues/51) + [#91](https://code.castopod.org/adaures/castopod/issues/91) + [#92](https://code.castopod.org/adaures/castopod/issues/92) + [#88](https://code.castopod.org/adaures/castopod/issues/88) +- **fonts:** replace Montserrat with Inter for better readablity + ([bfa11d0](https://code.castopod.org/adaures/castopod/commit/bfa11d007d04b8ac714c8cf3b8050a6aaf177a26)) +- **GDPR:** add GDPR.yml file to public/.well-known/ + ([86bccc3](https://code.castopod.org/adaures/castopod/commit/86bccc3d5cc9562b89196f1766ac91cdc8ad786d)) +- **gdpr:** add purpose for granting access to premium content + ([47d6d81](https://code.castopod.org/adaures/castopod/commit/47d6d81b798ec3ed467e0f4339c98c8a6b80cecd)) +- **home:** sort podcasts by recent activity + add dropdown menu to choose + between sorting options + ([7b89da6](https://code.castopod.org/adaures/castopod/commit/7b89da6106c150708782d39ed2742fe416c41e89)), + closes [#164](https://code.castopod.org/adaures/castopod/issues/164) +- **housekeeping:** add clear_cache option to flush redis or files cache + ([99bfac0](https://code.castopod.org/adaures/castopod/commit/99bfac0b428a4bc6fe8bfd10a355dfd93f42ba5c)) +- **i18n:** add 7 new languages + update german translations + ([d021abb](https://code.castopod.org/adaures/castopod/commit/d021abb52f5525d93810e25df2b453c918d7bc8b)) +- **i18n:** add german language as supported locale + create Language files from + english source + ([c220b31](https://code.castopod.org/adaures/castopod/commit/c220b310ed59cad188af044b1fed0c39efc7da5b)) +- **i18n:** add Norwegian Nynorsk to supported locales + ([ced61fc](https://code.castopod.org/adaures/castopod/commit/ced61fc2364f954c1f6e0208b572faf5741498a8)) +- **i18n:** add Polish translation + ([2d83b44](https://code.castopod.org/adaures/castopod/commit/2d83b44add9e4e00766a1f326377ed892f48ad73)) +- **i18n:** add Spanish to supported locales + ([e340b54](https://code.castopod.org/adaures/castopod/commit/e340b54a84d7dcdf9ba910fe7ff39c453fac0968)) +- **i18n:** add support for German and Brazilian Portuguese languages + ([c9b9fe4](https://code.castopod.org/adaures/castopod/commit/c9b9fe4ee893de9a1df7f8269c39d08a90d205d6)) +- **i18n:** add support for Simplified Chinese (zh-Hans) and Catalan (ca) + locales + ([48d1443](https://code.castopod.org/adaures/castopod/commit/48d14434727c3310a391160c7af02c56b7e20425)) +- **icons:** add default icons for podcasting, social and funding platforms + + remove complex icons + ([5bcdfeb](https://code.castopod.org/adaures/castopod/commit/5bcdfebe6489b5d6b90f3c828b014ec4e9a7e7e1)), + closes [#166](https://code.castopod.org/adaures/castopod/issues/166) + [#167](https://code.castopod.org/adaures/castopod/issues/167) + [#170](https://code.castopod.org/adaures/castopod/issues/170) +- **icons:** add podnews icon to podcasting platforms + ([5f42355](https://code.castopod.org/adaures/castopod/commit/5f423557c2b78fd7c38c5e0caab6c6c80d21e36e)), + closes [#190](https://code.castopod.org/adaures/castopod/issues/190) +- import podcast from an rss feed url + ([9a5d5a1](https://code.castopod.org/adaures/castopod/commit/9a5d5a15b4945eb319da9e999c4ca60a0a4f6d2d)), + closes [#21](https://code.castopod.org/adaures/castopod/issues/21) +- integrate stylized form components and update podcast edit page + ([6536729](https://code.castopod.org/adaures/castopod/commit/653672954606a23796e8a7bda3c34fd6b92f84e0)) +- make displayed publication time as relative time using @github/time-elements + ([230e139](https://code.castopod.org/adaures/castopod/commit/230e139e43324b9ebef06ca8f6e13b3d9a7bdc70)) +- make episode description more visible on episode pages + ([90533be](https://code.castopod.org/adaures/castopod/commit/90533be0298249e5527870c01329fce5f94ec2dc)), + closes [#171](https://code.castopod.org/adaures/castopod/issues/171) +- **map:** display geolocated episodes on a map page + ([4357cc2](https://code.castopod.org/adaures/castopod/commit/4357cc25ccc585ce398035c1c25d566b6a9df775)) +- **media:** clean media api + create an entity per media type + ([fafaa7e](https://code.castopod.org/adaures/castopod/commit/fafaa7e689b17f09a2b056081fa1f4fc53bf716b)) +- **media:** save audio, images, transcripts and chapters to media for episode + and persons + ([58e2a00](https://code.castopod.org/adaures/castopod/commit/58e2a00a87fa7d5b188e13cc521d94f0cfddba50)) +- **meta-tags:** add activitypub alternate links to podcast, episode, comment + and post pages + ([bd61752](https://code.castopod.org/adaures/castopod/commit/bd61752be2f574323b05d1d0aee0df55adf9a74e)) +- minor corrections to some tables + ([3bf9420](https://code.castopod.org/adaures/castopod/commit/3bf9420b5956a501b3b24405d243a71a928d6086)) +- **monetization:** add Web Monetization support + ([96a6026](https://code.castopod.org/adaures/castopod/commit/96a6026f1db452085360f5fe248de82a2ec06468)) +- **nodeinfo2:** add .well-known route for nodeinfo2 containing metadata about + the castopod instance + ([88fddc8](https://code.castopod.org/adaures/castopod/commit/88fddc81d730978f2a4d8a671936b54041e3fe45)) +- **partner:** add link and image in episode description + ([ad07bb9](https://code.castopod.org/adaures/castopod/commit/ad07bb9330dc9493813368e969e1f3a3def44614)) +- **person:** add podcastindex.org namespace person tag + ([8acd011](https://code.castopod.org/adaures/castopod/commit/8acd011f13e99492ef4b44b327685bb006fe5f8f)) +- **platforms:** add AntennaPod + ([53e9cfd](https://code.castopod.org/adaures/castopod/commit/53e9cfd61c794b1539e9d4691d3c4e73c4b7aaa7)) +- **platforms:** add Fediverse and some funding platforms, add link on logo + ([afc3d50](https://code.castopod.org/adaures/castopod/commit/afc3d50289bb4173e0697d109ffe72f6814b93d1)) +- **platforms:** add helloasso + ([16cb993](https://code.castopod.org/adaures/castopod/commit/16cb993ee6e28987a840fc27a9c2c73794c67697)) +- **platforms:** add missing newpodcastapps.com's platforms + ([92dd370](https://code.castopod.org/adaures/castopod/commit/92dd370e2f9a464edd26cddcde96d0e16f91548d)) +- **platforms:** add pod.link + ([3d7a232](https://code.castopod.org/adaures/castopod/commit/3d7a2320ddd116e4a311605421126aff57243219)) +- **platforms:** add Podcast Index + ([ad52b1c](https://code.castopod.org/adaures/castopod/commit/ad52b1cc2b7d0bc844970214d205961a7196b4a9)) +- **platforms:** add podfriend + ([9fdc8d3](https://code.castopod.org/adaures/castopod/commit/9fdc8d32930234c7ffd2be6892be57febcef1086)) +- **podcast-form:** add new_feed_url field to set an url when changing domain or + host + ([e7eec48](https://code.castopod.org/adaures/castopod/commit/e7eec48e7bc06a9aa907db01ed3e5b536e7dd8be)) +- **podcast-form:** update routes and redirect to podcast page + ([12ce905](https://code.castopod.org/adaures/castopod/commit/12ce905799002dc9c07e6de092342d30ba9fd7d8)) +- **podcast:** create a podcast using form + ([1202ba3](https://code.castopod.org/adaures/castopod/commit/1202ba3545f521097c60a6a2af95e70527cd1d34)) +- **podcasting 2.0:** update podcast:social tag to adhere to latest spec + ([a597cf4](https://code.castopod.org/adaures/castopod/commit/a597cf4ecfa6807a3413177d99c816056a7e7c45)) +- prefill season and episode numbers + set episode number as mandatory for + serial podcasts + ([07d740b](https://code.castopod.org/adaures/castopod/commit/07d740b79f9283e389e723954f680f909ce5de4a)), + closes [#134](https://code.castopod.org/adaures/castopod/issues/134) + [#136](https://code.castopod.org/adaures/castopod/issues/136) +- **public-ui:** adapt public podcast and episode pages to wireframes + ([40a0535](https://code.castopod.org/adaures/castopod/commit/40a0535fc1bc12a24994b651f5e00b35995cbdda)), + closes [#30](https://code.castopod.org/adaures/castopod/issues/30) + [#13](https://code.castopod.org/adaures/castopod/issues/13) +- **pwa:** add service-worker + webmanifest for each podcasts to have them + install on devices + ([fee2c1c](https://code.castopod.org/adaures/castopod/commit/fee2c1c0d0d03c4ff0a6a207b0a5e0c22bb7b13a)) +- redesign public podcast and episode pages + remove any information clutter for + better ux + ([9321400](https://code.castopod.org/adaures/castopod/commit/932140077c671f0486a2cd08ceb6126c7ecde87f)) +- replace form helper functions with components in admin template + ([e64548b](https://code.castopod.org/adaures/castopod/commit/e64548b982ba47ff35f2272e2e30dd85eeba950b)) +- replace slug field with interactive permalink component + ([578022b](https://code.castopod.org/adaures/castopod/commit/578022b8c5163ffaf8db5870ed5ec9d5d9536477)) +- restyle episode and person cards + add focus style to interactive elements for + a11y + ([a505a1d](https://code.castopod.org/adaures/castopod/commit/a505a1de56e8e3056379bd60d0595f432e294728)) +- **rss:** add ˂podcast:guid˃ tag for channel + ([1fab10e](https://code.castopod.org/adaures/castopod/commit/1fab10eb0d63bb7c3edf34ffe691e2aec2c2e43c)) +- **rss:** add podcast-namespace tags for platforms + previousUrl tag + ([dbba8dc](https://code.castopod.org/adaures/castopod/commit/dbba8dc58133967c778514268cbfed8098ed1dbc)), + closes [#73](https://code.castopod.org/adaures/castopod/issues/73) + [#75](https://code.castopod.org/adaures/castopod/issues/75) + [#76](https://code.castopod.org/adaures/castopod/issues/76) + [#80](https://code.castopod.org/adaures/castopod/issues/80) +- **rss:** add podcast:comments tag to link to episode comments + ([32e8c7c](https://code.castopod.org/adaures/castopod/commit/32e8c7c16a61ffe08e2f3bfbdeda556811a0358c)) +- **rss:** add podcast:location tag + ([c0a2282](https://code.castopod.org/adaures/castopod/commit/c0a22829bd87d48535a86e60c6cd7280e44683a2)) +- **rss:** add rss feed route without the `.xml` extension + ([94c0b7c](https://code.castopod.org/adaures/castopod/commit/94c0b7c15920dae9ade5cdc79c7996dbfe82ba05)), + closes [#247](https://code.castopod.org/adaures/castopod/issues/247) +- **rss:** add soundbites according to the podcastindex specs + ([6b34617](https://code.castopod.org/adaures/castopod/commit/6b34617d07c70522cb941e96d91d9987493413eb)), + closes [#83](https://code.castopod.org/adaures/castopod/issues/83) +- **rss:** add transcript and chapters support + ([e769d83](https://code.castopod.org/adaures/castopod/commit/e769d83a932c169e52a630a17cd4dd8ac5cebaf6)), + closes [#72](https://code.castopod.org/adaures/castopod/issues/72) + [#82](https://code.castopod.org/adaures/castopod/issues/82) +- **rss:** generate rss feed from podcast entity + ([c815ecd](https://code.castopod.org/adaures/castopod/commit/c815ecd6640931fee0895f80908a3ddfac482666)) +- **rss:** update monetization tag so that it meets PodcastIndex requirements + ([4c7ecbe](https://code.castopod.org/adaures/castopod/commit/4c7ecbee83950e5f9f2482cedaab18a1ac9bfc9e)) +- **select:** enhance select input with choices.js + ([910d457](https://code.castopod.org/adaures/castopod/commit/910d457cf843e0fc334b3505a4727d51633395ac)) - set app parameter forceGlobalSecureRequests = true forcing requests to go through https - ([d9dff1b](https://code.podlibre.org/podlibre/castopod-host/commit/d9dff1b8bf89c8b526ad6cb89f98a1f160d49117)) + ([d9dff1b](https://code.castopod.org/adaures/castopod/commit/d9dff1b8bf89c8b526ad6cb89f98a1f160d49117)) +- set podcast / episode description in the pages description meta tag + ([1c4a504](https://code.castopod.org/adaures/castopod/commit/1c4a50442bea2d3449efce9c5ff1c80743152f55)), + closes [#44](https://code.castopod.org/adaures/castopod/issues/44) +- **settings:** add general config for instance (site name, description and + icon) + ([5c56f3e](https://code.castopod.org/adaures/castopod/commit/5c56f3e6f00a61af2ccf50811c155c325f2b10fa)) +- **settings:** add theme settings to set an accent color for all public pages + ([5c529a8](https://code.castopod.org/adaures/castopod/commit/5c529a83aa6d6147d94e5aee996e6b0ab02f0ce4)) +- simplify podcast page's layout for better ux + ([2c0efc6](https://code.castopod.org/adaures/castopod/commit/2c0efc6563604dd067be88cfc9ddd88a01745e64)) +- **soundbites:** add soundbite list and creation forms with audio-clipper + component + ([de19317](https://code.castopod.org/adaures/castopod/commit/de19317138a2106deb825c1eed7dda036ed7dac3)) +- style file inputs using tailwind's file class + ([8208ab6](https://code.castopod.org/adaures/castopod/commit/8208ab6785aae8c49f78eb9ac8cd53d77ec8e5e5)) +- **themes:** add ViewThemes library to set views in root themes folder + ([7a27676](https://code.castopod.org/adaures/castopod/commit/7a276764e6a1ee3619d9d3488f6163215db75338)) +- **themes:** set different default banner per theme + ([11c916f](https://code.castopod.org/adaures/castopod/commit/11c916fe433eb749ac32230c48e256057564cbb0)) +- **themes:** set generic css variables for colors to enable instance themes + ([a746a78](https://code.castopod.org/adaures/castopod/commit/a746a781b4bfc78209cf8302c6d7bb3cb452e446)) +- toggle podcast sidebar on smaller screens + ([f0205ec](https://code.castopod.org/adaures/castopod/commit/f0205ec274414e881cba40d6776126f05eaee583)) +- **transcript:** parse srt subtitles into json file + add max file size info + below audio file input + ([0098761](https://code.castopod.org/adaures/castopod/commit/00987610a068c8d6cdd4421ea16585fa037eb61a)) +- **ui:** create ViewComponents library to enable building class and view files + components + ([94872f2](https://code.castopod.org/adaures/castopod/commit/94872f2338e6025c2f3770be256160838dae9003)) +- update analytics so to meet IABv2 requirements + ([03e23a2](https://code.castopod.org/adaures/castopod/commit/03e23a28bf9b1b73fba55352c36a8cd6cc8ae729)), + closes [#10](https://code.castopod.org/adaures/castopod/issues/10) +- update pine colors + create charts components + ([a50abc1](https://code.castopod.org/adaures/castopod/commit/a50abc138d4997b564e3065b37504cda5ce62da6)) +- **users:** add myth-auth to handle users crud + add admin gateway only + accessible by login + ([c63a077](https://code.castopod.org/adaures/castopod/commit/c63a077618c61b4cde7f25ffc650a4b0e1495f44)), + closes [#11](https://code.castopod.org/adaures/castopod/issues/11) - **ux:** remove admin dashboard and redirect directly to podcast list - ([27c48b8](https://code.podlibre.org/podlibre/castopod-host/commit/27c48b8fa930b33e5e15f0c8685e468e857ca9cd)) -- add cache to ActivityPub sql queries + cache activity and note pages - ([2d297f4](https://code.podlibre.org/podlibre/castopod-host/commit/2d297f45b3d7ef6e8711875a0b9b908e878115fa)) + ([27c48b8](https://code.castopod.org/adaures/castopod/commit/27c48b8fa930b33e5e15f0c8685e468e857ca9cd)) +- **video-clip:** add video-clip page with video preview + logs + ([42538dd](https://code.castopod.org/adaures/castopod/commit/42538dd7577be0ffe59b4fdfadbd76cc89e5ef30)) +- **video-clip:** generate video clips in the bg using a cron job + add video + clip page + tidy up UI + ([db0e427](https://code.castopod.org/adaures/castopod/commit/db0e4272bd6d307c562e1f961d2747cb62de0f35)) +- **video-clips:** add dimensions for portrait and squared formats + ([3af404d](https://code.castopod.org/adaures/castopod/commit/3af404da3dd1901c78cc7e1778fc225f6716207d)) +- **video-clips:** add new themes + add castopod logo as a watermark + ([1d1490b](https://code.castopod.org/adaures/castopod/commit/1d1490b06a1f5ecb10b3b98a72efc55d09c10944)) +- **video-clips:** add route for scheduled video clips + list video clips with + status + ([2065ebb](https://code.castopod.org/adaures/castopod/commit/2065ebbee5e3d0f890ac90b55ca984f1d62a184c)) +- **video-clips:** allow episodeNumbering text to stand in the indent of + episodeTitle paragraph + ([71a063d](https://code.castopod.org/adaures/castopod/commit/71a063dac311cb21639801fbae6af7c5106c2699)) +- **video-clips:** generate a 16:9 video using ffmpeg + ([35aa7ea](https://code.castopod.org/adaures/castopod/commit/35aa7ea5d9a339b3e6f745137282268d69fe2231)) +- **video-clips:** generate subtitles clip using transcript json to have + subtitles accross video + ([3ce07e4](https://code.castopod.org/adaures/castopod/commit/3ce07e455d171e29be30d8ad45055510eb8d363c)) +- **video-clips:** replace hardcoded colors with config's theme colors + ([e462abf](https://code.castopod.org/adaures/castopod/commit/e462abf6d660e41d2170c52caf45704008de58e9)) +- **vite:** add vite config to decouple it from CI_ENVIRONMENT + ([8721719](https://code.castopod.org/adaures/castopod/commit/8721719cd7cf32e94823541eafaba1e9309355a8)) +- write id3v2 tags to episode's audio file + ([4651d01](https://code.castopod.org/adaures/castopod/commit/4651d01a84ff3ea8433a8ae26cfd750a1ec9e88d)) ### Performance Improvements - **cache:** update CI4 to use cache's deleteMatching method - ([54b84f9](https://code.podlibre.org/podlibre/castopod-host/commit/54b84f96843af13f579fea49102c8c2ef81b0a54)) + ([54b84f9](https://code.castopod.org/adaures/castopod/commit/54b84f96843af13f579fea49102c8c2ef81b0a54)) +- **cache:** use deleteMatching method to prevent forgetting cached elements in + models + ([76afc0c](https://code.castopod.org/adaures/castopod/commit/76afc0cfa2feb087697bae4bc138e4956873dd62)) +- defer javascript + lazy load images for faster page loads + ([f0685e4](https://code.castopod.org/adaures/castopod/commit/f0685e44799dfb494592ff97841c0ae035381db8)) - **docker:** add redis caching service for development - ([05ace8c](https://code.podlibre.org/podlibre/castopod-host/commit/05ace8cff2ef02d19abd40097ac5546dca6a54ca)) - -# [1.0.0-alpha.53](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.52...v1.0.0-alpha.53) (2021-04-16) - -### Bug Fixes - -- check that note has a preview_card_id before displaying it - ([acb8b3a](https://code.podlibre.org/podlibre/castopod/commit/acb8b3a40172ccb184ffe544760601d756692e6c)), - closes [#114](https://code.podlibre.org/podlibre/castopod/issues/114) - -# [1.0.0-alpha.52](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.51...v1.0.0-alpha.52) (2021-04-16) - -### Bug Fixes - -- **avatar:** use default avatar when no avatar url has been set - ([9d23c7e](https://code.podlibre.org/podlibre/castopod/commit/9d23c7e7e142c6cf1a1418e37e41d711064593c4)), - closes [#111](https://code.podlibre.org/podlibre/castopod/issues/111) - -# [1.0.0-alpha.51](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.50...v1.0.0-alpha.51) (2021-04-15) - -### Bug Fixes - -- **interact-as:** set actor_id instead of podcast id upon login event - ([5dfade7](https://code.podlibre.org/podlibre/castopod/commit/5dfade7cf37f339c56d2e577c679b88a1b1d9336)), - closes [#104](https://code.podlibre.org/podlibre/castopod/issues/104) - -# [1.0.0-alpha.50](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.49...v1.0.0-alpha.50) (2021-04-14) - -### Bug Fixes - -- **persons:** prevent overflow of persons list by adding horizontal scroll - ([9e8995d](https://code.podlibre.org/podlibre/castopod/commit/9e8995dc6e039032cc65f87895cf770f99e8b244)) - -# [1.0.0-alpha.49](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.48...v1.0.0-alpha.49) (2021-04-12) - -### Bug Fixes - -- **multiselect:** add missing class names in choices options for purge to work - properly - ([719538d](https://code.podlibre.org/podlibre/castopod/commit/719538d0ccb28af3c3c5e1a4b6468d4b772fe819)) - -# [1.0.0-alpha.48](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.47...v1.0.0-alpha.48) (2021-04-10) - -### Bug Fixes - -- **import-with-escaped-characters:** remove \CodeIgniter\HTTP\URI in - download_file, closes - [#103](https://code.podlibre.org/podlibre/castopod/issues/103) - ([35b5be0](https://code.podlibre.org/podlibre/castopod/commit/35b5be095ff54d27acec1610a846ec0cdbdf1d65)) - -# [1.0.0-alpha.47](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.46...v1.0.0-alpha.47) (2021-04-10) - -### Bug Fixes - -- **episodeCount:** add missing brackets to French language file - ([c1b4112](https://code.podlibre.org/podlibre/castopod/commit/c1b411265ad9b06e95a8b097ecf73445b88dcb45)) - -# [1.0.0-alpha.46](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.45...v1.0.0-alpha.46) (2021-04-09) - -### Bug Fixes - -- **episodes-page:** handle defaultQuery being null when no podcast episodes - ([15183b7](https://code.podlibre.org/podlibre/castopod/commit/15183b7eab57dac007bcdfa8c3651239de1ae05a)), - closes [#100](https://code.podlibre.org/podlibre/castopod/issues/100) - -# [1.0.0-alpha.45](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.44...v1.0.0-alpha.45) (2021-04-08) - -### Bug Fixes - -- add head request to analytics_hit route - ([f0a2f0b](https://code.podlibre.org/podlibre/castopod/commit/f0a2f0bea491ca91976b351bb79837e95c9d094b)) - -# [1.0.0-alpha.44](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.43...v1.0.0-alpha.44) (2021-04-08) - -### Bug Fixes - -- **rss:** set ❬itunes:author❭ tag to owner_name if publisher not specified - ([2271c14](https://code.podlibre.org/podlibre/castopod/commit/2271c1445b1ded12bc53b5d23b5e59d12b17c71a)), - closes [#96](https://code.podlibre.org/podlibre/castopod/issues/96) - -# [1.0.0-alpha.43](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.42...v1.0.0-alpha.43) (2021-04-08) - -### Bug Fixes - -- **episode-form:** show warning to set `memory_limit`, `upload_max_filesize` & - `post_max_size` - ([3b3c218](https://code.podlibre.org/podlibre/castopod/commit/3b3c218b9c868e9f12c54d7670e69d84c9ee79c0)), - closes [#5](https://code.podlibre.org/podlibre/castopod/issues/5) - [#86](https://code.podlibre.org/podlibre/castopod/issues/86) - -# [1.0.0-alpha.42](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.41...v1.0.0-alpha.42) (2021-04-02) - -### Features - -- **fediverse:** implement activitypub protocols + update user interface - ([2f525c0](https://code.podlibre.org/podlibre/castopod/commit/2f525c0f6e44d320bff16e22c223481923ba683e)), - closes [#69](https://code.podlibre.org/podlibre/castopod/issues/69) - [#65](https://code.podlibre.org/podlibre/castopod/issues/65) - [#85](https://code.podlibre.org/podlibre/castopod/issues/85) - [#51](https://code.podlibre.org/podlibre/castopod/issues/51) - [#91](https://code.podlibre.org/podlibre/castopod/issues/91) - [#92](https://code.podlibre.org/podlibre/castopod/issues/92) - [#88](https://code.podlibre.org/podlibre/castopod/issues/88) - -# [1.0.0-alpha.41](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.40...v1.0.0-alpha.41) (2021-03-30) - -### Features - -- **partner:** add link and image in episode description - ([ad07bb9](https://code.podlibre.org/podlibre/castopod/commit/ad07bb9330dc9493813368e969e1f3a3def44614)) - -# [1.0.0-alpha.40](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.39...v1.0.0-alpha.40) (2021-03-19) - -### Features - -- **custom-rss:** add custom xml tag injection in rss feed for ❬channel❭ and - ❬item❭ - ([6ecdaad](https://code.podlibre.org/podlibre/castopod/commit/6ecdaad911d06b7f7a2b7d24710968c7eb9118f6)) - -# [1.0.0-alpha.39](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.38...v1.0.0-alpha.39) (2021-03-01) - -### Bug Fixes - -- **embeddable-player:** enable any ancestor when X-Frame-Options is set on - server - ([44a4962](https://code.podlibre.org/podlibre/castopod/commit/44a4962e0b7e3ed87e9914b4e7792a0d52330ff8)) - -# [1.0.0-alpha.38](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.37...v1.0.0-alpha.38) (2021-02-27) - -### Features - -- **embeddable-player:** add embeddable player widget - ([141788f](https://code.podlibre.org/podlibre/castopod/commit/141788fa089f9dedc8956c64ca515a4a4625f904)) - -# [1.0.0-alpha.37](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.36...v1.0.0-alpha.37) (2021-02-17) - -### Bug Fixes - -- **import:** remove query string from files url - ([109c4aa](https://code.podlibre.org/podlibre/castopod/commit/109c4aa1afb72dd8b99c0302d74a7fef5a38638e)) - -# [1.0.0-alpha.36](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.35...v1.0.0-alpha.36) (2021-02-16) - -### Features - -- **platforms:** add pod.link - ([3d7a232](https://code.podlibre.org/podlibre/castopod/commit/3d7a2320ddd116e4a311605421126aff57243219)) - -# [1.0.0-alpha.35](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.34...v1.0.0-alpha.35) (2021-02-12) - -### Bug Fixes - -- **admin:** save block and lock switches - ([b66c0af](https://code.podlibre.org/podlibre/castopod/commit/b66c0afc8fab2e338402a9a4f8105e5f5459e208)) - -# [1.0.0-alpha.34](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.33...v1.0.0-alpha.34) (2021-02-11) - -### Bug Fixes - -- **rss-import:** add Castopod user-agent, handle redirects for downloaded - files, add Content namespace - ([214243b](https://code.podlibre.org/podlibre/castopod/commit/214243b3fec4937e45ef1ceaba1149004cdf3b44)) - -# [1.0.0-alpha.33](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.32...v1.0.0-alpha.33) (2021-02-10) - -### Features - -- **platforms:** add helloasso - ([16cb993](https://code.podlibre.org/podlibre/castopod/commit/16cb993ee6e28987a840fc27a9c2c73794c67697)) - -# [1.0.0-alpha.32](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.31...v1.0.0-alpha.32) (2021-02-10) - -### Features - -- **person:** add podcastindex.org namespace person tag - ([8acd011](https://code.podlibre.org/podlibre/castopod/commit/8acd011f13e99492ef4b44b327685bb006fe5f8f)) - -# [1.0.0-alpha.31](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.30...v1.0.0-alpha.31) (2020-12-23) - -### Features - -- **rss:** add podcast:location tag - ([c0a2282](https://code.podlibre.org/podlibre/castopod/commit/c0a22829bd87d48535a86e60c6cd7280e44683a2)) - -# [1.0.0-alpha.30](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.29...v1.0.0-alpha.30) (2020-12-21) - -### Features - -- **rss:** update monetization tag so that it meets PodcastIndex requirements - ([4c7ecbe](https://code.podlibre.org/podlibre/castopod/commit/4c7ecbee83950e5f9f2482cedaab18a1ac9bfc9e)) - -# [1.0.0-alpha.29](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.28...v1.0.0-alpha.29) (2020-12-10) - -### Bug Fixes - -- **episodes:** add publication status + set publication date to null when none - has been set - ([d882981](https://code.podlibre.org/podlibre/castopod/commit/d882981b3a86c81921ce6b07d4cf61fc13983689)), - closes [#70](https://code.podlibre.org/podlibre/castopod/issues/70) + ([05ace8c](https://code.castopod.org/adaures/castopod/commit/05ace8cff2ef02d19abd40097ac5546dca6a54ca)) ### Reverts +- **install:** redirect to install in homepage if no database was set + ([73f094d](https://code.castopod.org/adaures/castopod/commit/73f094daf26a8cf75e39ebff1eeb7f9039276312)) +- set deprecated config options back in App config + ([433745f](https://code.castopod.org/adaures/castopod/commit/433745f194c73407999b207090478563283876a5)) - **soundbites:** remove soundbite table from episode's public page - ([5dc0f19](https://code.podlibre.org/podlibre/castopod/commit/5dc0f19656de0d764f627d6ae78a9e306c901835)) - -# [1.0.0-alpha.28](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.27...v1.0.0-alpha.28) (2020-12-07) - -### Features - -- **rss:** add soundbites according to the podcastindex specs - ([6b34617](https://code.podlibre.org/podlibre/castopod/commit/6b34617d07c70522cb941e96d91d9987493413eb)), - closes [#83](https://code.podlibre.org/podlibre/castopod/issues/83) - -# [1.0.0-alpha.27](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.26...v1.0.0-alpha.27) (2020-12-07) - -### Features - -- **platforms:** add AntennaPod - ([53e9cfd](https://code.podlibre.org/podlibre/castopod/commit/53e9cfd61c794b1539e9d4691d3c4e73c4b7aaa7)) - -# [1.0.0-alpha.26](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.25...v1.0.0-alpha.26) (2020-11-30) - -### Bug Fixes - -- **analytics:** update service management so that it works with new OPAWG slug - values - ([7fe9d42](https://code.podlibre.org/podlibre/castopod/commit/7fe9d42500ade2c6fa3ff4365b4affc475af0e51)) - -# [1.0.0-alpha.25](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.24...v1.0.0-alpha.25) (2020-11-30) - -### Features - -- **platforms:** add podfriend - ([9fdc8d3](https://code.podlibre.org/podlibre/castopod/commit/9fdc8d32930234c7ffd2be6892be57febcef1086)) - -# [1.0.0-alpha.24](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.23...v1.0.0-alpha.24) (2020-11-26) - -### Features - -- **monetization:** add Web Monetization support - ([96a6026](https://code.podlibre.org/podlibre/castopod/commit/96a6026f1db452085360f5fe248de82a2ec06468)) - -# [1.0.0-alpha.23](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.22...v1.0.0-alpha.23) (2020-11-24) - -### Bug Fixes - -- define podcastNamespaceLink value - ([0d744d2](https://code.podlibre.org/podlibre/castopod/commit/0d744d212df0d070ceea185068eaf2746e1ccd48)) - -# [1.0.0-alpha.22](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.21...v1.0.0-alpha.22) (2020-11-24) - -### Features - -- **rss:** add transcript and chapters support - ([e769d83](https://code.podlibre.org/podlibre/castopod/commit/e769d83a932c169e52a630a17cd4dd8ac5cebaf6)), - closes [#72](https://code.podlibre.org/podlibre/castopod/issues/72) - [#82](https://code.podlibre.org/podlibre/castopod/issues/82) - -# [1.0.0-alpha.21](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.20...v1.0.0-alpha.21) (2020-11-24) - -### Features - -- **platforms:** add Fediverse and some funding platforms, add link on logo - ([afc3d50](https://code.podlibre.org/podlibre/castopod/commit/afc3d50289bb4173e0697d109ffe72f6814b93d1)) - -# [1.0.0-alpha.20](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.19...v1.0.0-alpha.20) (2020-11-24) - -### Bug Fixes - -- **import:** use tag when no is present - ([20e607a](https://code.podlibre.org/podlibre/castopod/commit/20e607afb755bc75056041738fa7cbf6723d754c)) - -### Features - -- **rss:** add podcast-namespace tags for platforms + previousUrl tag - ([dbba8dc](https://code.podlibre.org/podlibre/castopod/commit/dbba8dc58133967c778514268cbfed8098ed1dbc)), - closes [#73](https://code.podlibre.org/podlibre/castopod/issues/73) - [#75](https://code.podlibre.org/podlibre/castopod/issues/75) - [#76](https://code.podlibre.org/podlibre/castopod/issues/76) - [#80](https://code.podlibre.org/podlibre/castopod/issues/80) - -# [1.0.0-alpha.19](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.18...v1.0.0-alpha.19) (2020-11-13) - -### Bug Fixes - -- handle HEAD requests on podcast_feed route - ([74b2640](https://code.podlibre.org/podlibre/castopod/commit/74b2640f2a25c4cd6fd8835fc492c2a6893d4950)), - closes [#79](https://code.podlibre.org/podlibre/castopod/issues/79) - -# [1.0.0-alpha.18](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.17...v1.0.0-alpha.18) (2020-11-09) - -### Features - -- **platforms:** add Podcast Index - ([ad52b1c](https://code.podlibre.org/podlibre/castopod/commit/ad52b1cc2b7d0bc844970214d205961a7196b4a9)) - -# [1.0.0-alpha.17](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.16...v1.0.0-alpha.17) (2020-11-05) - -### Bug Fixes - -- **open-graph:** replace non existant episode description to podcast - description in podcast page - ([b02584e](https://code.podlibre.org/podlibre/castopod/commit/b02584ee609af1ad1b5680cc28208d113eb0410b)) - -# [1.0.0-alpha.16](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.15...v1.0.0-alpha.16) (2020-11-04) - -### Features - -- add Open Graph and Twitter meta tags - ([af970b8](https://code.podlibre.org/podlibre/castopod/commit/af970b8bac949e4c63047e04aca1b7403a4e8deb)), - closes [#41](https://code.podlibre.org/podlibre/castopod/issues/41) - -# [1.0.0-alpha.15](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.14...v1.0.0-alpha.15) (2020-11-03) - -### Features - -- **analytics:** add 'other' group to pie charts in order to display more - accurate data - ([73acef9](https://code.podlibre.org/podlibre/castopod/commit/73acef933ff3485987afc5157de022910876fc12)) - -# [1.0.0-alpha.14](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.13...v1.0.0-alpha.14) (2020-11-02) - -### Features - -- **analytics:** add weekday and hour bar charts - ([8ab3132](https://code.podlibre.org/podlibre/castopod/commit/8ab313296bb4a254ab05e90b17d896039839b784)) - -# [1.0.0-alpha.13](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.12...v1.0.0-alpha.13) (2020-10-29) - -### Bug Fixes - -- **episodes-table:** set descriptions to be not null - ([6774ec1](https://code.podlibre.org/podlibre/castopod/commit/6774ec10fa78527be6b7548ca1dc34ad0ada090c)) - -### Features - -- add episode_numbering() component helper to display episode and season numbers - ([3f4a6bd](https://code.podlibre.org/podlibre/castopod/commit/3f4a6bd0b9f870f16107a41b102b6bf734868198)) -- **episodes:** replace all audio file URL parameters with base64 encoded data - ([e1f65cd](https://code.podlibre.org/podlibre/castopod/commit/e1f65cd3b53353a30d4ab6eb5312393cf04a1676)) - -# [1.0.0-alpha.12](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.11...v1.0.0-alpha.12) (2020-10-26) - -### Bug Fixes - -- replace getWebEnclosureUrl with getEnclosureWebUrl - ([8122cea](https://code.podlibre.org/podlibre/castopod/commit/8122ceaf8a70050f14b3078f28b024e7d7cdb9ac)) - -# [1.0.0-alpha.11](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.10...v1.0.0-alpha.11) (2020-10-26) - -### Features - -- add CDN url - ([972bcbf](https://code.podlibre.org/podlibre/castopod/commit/972bcbf65ee119b8641ca3c4e5c0e8cf9ca8dd4f)), - closes [#37](https://code.podlibre.org/podlibre/castopod/issues/37) - -# [1.0.0-alpha.10](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.9...v1.0.0-alpha.10) (2020-10-26) - -### Bug Fixes - -- **install:** redirect to host_url install route on instanceConfig validation - error - ([99250b1](https://code.podlibre.org/podlibre/castopod/commit/99250b1868657c249a447399c7ebc69e00d43d1a)) - -# [1.0.0-alpha.9](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.8...v1.0.0-alpha.9) (2020-10-26) - -### Features - -- display castopod version in admin footer - ([9f2574e](https://code.podlibre.org/podlibre/castopod/commit/9f2574e6fbb61dac4e1a4252dff30017685da5f0)), - closes [#68](https://code.podlibre.org/podlibre/castopod/issues/68) - -# [1.0.0-alpha.8](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.7...v1.0.0-alpha.8) (2020-10-22) - -### Features - -- **episodes:** schedule episode with future publication_date by using cache - expiration time - ([4f1e773](https://code.podlibre.org/podlibre/castopod/commit/4f1e773c0f9e4c2597f6c1b0a4773dfb34b2f203)), - closes [#47](https://code.podlibre.org/podlibre/castopod/issues/47) - -# [1.0.0-alpha.7](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.6...v1.0.0-alpha.7) (2020-10-21) - -### Features - -- **analytics:** add service name from rss user-agent - ([7202b98](https://code.podlibre.org/podlibre/castopod/commit/7202b9867bd59aafa8c338a4230fb5e5c55b24c6)) + ([5dc0f19](https://code.castopod.org/adaures/castopod/commit/5dc0f19656de0d764f627d6ae78a9e306c901835)) +- use basic input file for episodes audio files instead of button for better UX + ([d5f22fb](https://code.castopod.org/adaures/castopod/commit/d5f22fbb38c43d9b37df401eff655958a57cb40a)) ### BREAKING CHANGES - **analytics:** analytics_podcasts_by_player table and analytics_podcasts procedure were updated -# [1.0.0-alpha.6](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.5...v1.0.0-alpha.6) (2020-10-20) +# [1.0.0-beta.24](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.23...v1.0.0-beta.24) (2022-10-14) + +### Bug Fixes + +- **router:** trim URI slash to match same routes for URIs with and without + trailing slash + ([9e9375f](https://code.castopod.org/adaures/castopod/commit/9e9375f9a2cd6102f827b36ec521f4c86a557c00)) + +### Features + +- **episode:** add form to allow editing episode's publication date to a past + date + ([d783d16](https://code.castopod.org/adaures/castopod/commit/d783d16eb73d3f896a3dea39a766b4e963e53abf)), + closes [#97](https://code.castopod.org/adaures/castopod/issues/97) +- **rss:** add rss feed route without the `.xml` extension + ([94c0b7c](https://code.castopod.org/adaures/castopod/commit/94c0b7c15920dae9ade5cdc79c7996dbfe82ba05)), + closes [#247](https://code.castopod.org/adaures/castopod/issues/247) + +# [1.0.0-beta.23](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.22...v1.0.0-beta.23) (2022-09-29) + +### Bug Fixes + +- **premium-podcasts:** display unlock button in embed when premium episode + ([ca109ba](https://code.castopod.org/adaures/castopod/commit/ca109ba3a8a08e661fd2484454b1983c3418f15d)) +- **premium-podcasts:** remove cache in unlock form + redirect to podcast if + podcast is not premium + ([242352c](https://code.castopod.org/adaures/castopod/commit/242352c4d9cd936de14e8e8a5d78ebf1287b1f95)) +- **premium-podcasts:** return different cached page when podcast is unlocked + ([b1303c5](https://code.castopod.org/adaures/castopod/commit/b1303c525517498b0edfb9885ff36e08c72628b5)) + +### Features + +- add instructions on production error page to ease Castopod debugging process + ([9eab54e](https://code.castopod.org/adaures/castopod/commit/9eab54e0853ccb8300d9f9b743cd84aefbf06549)), + closes [#224](https://code.castopod.org/adaures/castopod/issues/224) +- add premium podcasts to manage subscriptions for premium episodes + ([3234500](https://code.castopod.org/adaures/castopod/commit/3234500e2d967438ad140f65da801a543f43775d)), + closes [#193](https://code.castopod.org/adaures/castopod/issues/193) +- **gdpr:** add purpose for granting access to premium content + ([47d6d81](https://code.castopod.org/adaures/castopod/commit/47d6d81b798ec3ed467e0f4339c98c8a6b80cecd)) + +# [1.0.0-beta.22](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2022-09-23) + +### Bug Fixes + +- **fediverse:** set default castopod avatar url when actor avatar is not + present + ([460f52f](https://code.castopod.org/adaures/castopod/commit/460f52f70e493d619c28632db6c698e88f0ebb5f)) +- **import:** set default episode type if not set + ([d7250ab](https://code.castopod.org/adaures/castopod/commit/d7250ab03f9b032830c575ad58b51c8d60b7a49a)) +- **input-component:** unset required attribute to prevent rendering it when + false + ([db9ac13](https://code.castopod.org/adaures/castopod/commit/db9ac13860bce58235a5da275910bea605a00626)) +- **notifications:** notify actors after activities insert / update using model + callback methods + ([e08555a](https://code.castopod.org/adaures/castopod/commit/e08555a4e9a6c15eeba18273c63403f82eddae35)) +- overwrite getActorById to return app's Actor entity + ([f2bc2f7](https://code.castopod.org/adaures/castopod/commit/f2bc2f7e01aa166faa627df6fe4d5ed4887c16e5)) +- remove heavy image cover data from audio file metadata + ([f74403b](https://code.castopod.org/adaures/castopod/commit/f74403bd7a5089b760603abe36264e7615be0e78)) +- set storage limit as disk_total_space instead of free space + ([7512e2e](https://code.castopod.org/adaures/castopod/commit/7512e2ed1ff5656cd63a4fc2524296dbb8b4164a)) +- **ui:** remove empty tooltip when hovering on sponsor button + ([40aa661](https://code.castopod.org/adaures/castopod/commit/40aa661289e1d1517fffcea5d257183bc9c458e4)) +- **users:** remove required roles input when editing user + prevent owner's + roles from being edited + ([1c8af75](https://code.castopod.org/adaures/castopod/commit/1c8af7550ba27d8c8473ae96acd21ad7731fd863)), + closes [#239](https://code.castopod.org/adaures/castopod/issues/239) +- **ux:** have podcast dashboard card link to podcast dashboard if only one + podcast in instance + ([7dabee5](https://code.castopod.org/adaures/castopod/commit/7dabee58a187abe92358d962da506a836e29cda3)) + +# [1.0.0-beta.21](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2022-09-06) + +### Bug Fixes + +- **email:** set the correct url in the activation and forgot emails + ([10fc6f1](https://code.castopod.org/adaures/castopod/commit/10fc6f17c6838a58348f32ccfd0cf05f9d3e172c)), + closes [#204](https://code.castopod.org/adaures/castopod/issues/204) +- **notifications:** add trigger after activities update + update insert trigger + ([e5d16e8](https://code.castopod.org/adaures/castopod/commit/e5d16e87119021fa5a43470d67ddfe5128e57f74)) + +### Features + +- **i18n:** add support for Simplified Chinese (zh-Hans) and Catalan (ca) + locales + ([48d1443](https://code.castopod.org/adaures/castopod/commit/48d14434727c3310a391160c7af02c56b7e20425)) + +# [1.0.0-beta.20](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2022-08-12) + +### Bug Fixes + +- add underline and semibold font weight for prose links to have them stand out + ([d4d8671](https://code.castopod.org/adaures/castopod/commit/d4d867121c50bded4176a53d7154cf1bb347e306)) +- **router:** check if Accept header is set before getting value + ([10a2ae0](https://code.castopod.org/adaures/castopod/commit/10a2ae02484672d6a0fbc6e7b943519c5ec16cb6)), + closes [#228](https://code.castopod.org/adaures/castopod/issues/228) +- **search-episodes:** add fallback sql query using LIKE for search query with + less than 4 characters + ([e66bf44](https://code.castopod.org/adaures/castopod/commit/e66bf44341175bc5a10fbf7dfa00b351e76136c2)), + closes [#236](https://code.castopod.org/adaures/castopod/issues/236) +- set interact_as_actor for user upon password reset + ([ad8f5f5](https://code.castopod.org/adaures/castopod/commit/ad8f5f5a0fac7b0b9cc10a0b86200f014aca7553)), + closes [#178](https://code.castopod.org/adaures/castopod/issues/178) + +### Features + +- add label to sponsor button on podcast page + ([c29c018](https://code.castopod.org/adaures/castopod/commit/c29c018c7a543fc9398b5d7d11f086123e2b33f2)), + closes [#162](https://code.castopod.org/adaures/castopod/issues/162) +- add notifications inbox for actors + ([999999e](https://code.castopod.org/adaures/castopod/commit/999999e3efab7b1aad7568e4fd114dc7bac04f38)), + closes [#215](https://code.castopod.org/adaures/castopod/issues/215) + +# [1.0.0-beta.19](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.18...v1.0.0-beta.19) (2022-07-21) + +### Bug Fixes + +- **episode-unpublish:** set consistent posts_counts' increments/decrements for + actors and episodes + ([8acdafd](https://code.castopod.org/adaures/castopod/commit/8acdafd26044e50a4d6ee451bf24ad66003c5bb3)), + closes [#233](https://code.castopod.org/adaures/castopod/issues/233) +- **get_browser_language:** return defaultLocale if browser doesn't send user + preferred language + ([9cc2996](https://code.castopod.org/adaures/castopod/commit/9cc299626181048b85b629bbe7f5806a1f5d21ff)) + +### Features + +- **episode-unpublish:** remove episode comments upon unpublish + ([78acd7f](https://code.castopod.org/adaures/castopod/commit/78acd7f5c057c82507d801c424040296dbaba586)) + +# [1.0.0-beta.18](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.17...v1.0.0-beta.18) (2022-07-07) + +### Bug Fixes + +- **player-styling:** revert vite to 2.8 to reference the player css + ([e07d3af](https://code.castopod.org/adaures/castopod/commit/e07d3afea9af85b8361227e000fb64b502781668)) + +### Features + +- add legalNoticeURL to app config for setting an external url to legal notice + ([711843a](https://code.castopod.org/adaures/castopod/commit/711843a0c81e1e2ec7a015431786df4ef32d5092)) + +# [1.0.0-beta.17](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2022-07-06) + +### Bug Fixes + +- explicitly cast seconds to int in iso8601_duration helper function + ([779653f](https://code.castopod.org/adaures/castopod/commit/779653f75b140942f731cbb238bc0667cc461307)) +- **housekeeping:** use EpisodeModel's builder to reset comments count + ([65e9c0b](https://code.castopod.org/adaures/castopod/commit/65e9c0b05ea4992884149cb4a4b071bf31a20a1a)) +- **rss:** round episode durations and soundbites + ([c9fb987](https://code.castopod.org/adaures/castopod/commit/c9fb987fcfbe17069ec68fdbc823777079ce574b)), + closes [#214](https://code.castopod.org/adaures/castopod/issues/214) +- **xml-editor:** prettify xml even without root node + ([ca55c24](https://code.castopod.org/adaures/castopod/commit/ca55c248d0562a8529071c1f10be12f40ef50dda)) + +### Features + +- add publish feature for podcasts and set draft by default + ([3d363f2](https://code.castopod.org/adaures/castopod/commit/3d363f2efe99836ac05c305a2fa683e342f06561)), + closes [#128](https://code.castopod.org/adaures/castopod/issues/128) + [#220](https://code.castopod.org/adaures/castopod/issues/220) +- **admin:** add instance wide dashboard with storage and bandwidth usage + ([b1a6c02](https://code.castopod.org/adaures/castopod/commit/b1a6c02e56fdc01a7ff69fa7e7dd8ea71380b7ba)), + closes [#216](https://code.castopod.org/adaures/castopod/issues/216) +- **datetime-picker:** set material_green theme to flatpickr + ([3ce6541](https://code.castopod.org/adaures/castopod/commit/3ce6541003260677e722a916ad6bc83ef47c4371)) + +# [1.0.0-beta.16](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2022-06-24) + +### Bug Fixes + +- change image size requirement hints + ([ea20206](https://code.castopod.org/adaures/castopod/commit/ea20206ee674eb54dd3ea188d2a2e2d41425df65)) + +### Features + +- add update rss feed feature for podcasts to import their latest episodes + ([5eb9dc1](https://code.castopod.org/adaures/castopod/commit/5eb9dc168eb9af04767829b76242c9120f55d46d)), + closes [#183](https://code.castopod.org/adaures/castopod/issues/183) +- **admin:** add search form in podcast episodes list + ([6be5d12](https://code.castopod.org/adaures/castopod/commit/6be5d12877342a7c56e25ea8dd15a975c6ce45ac)), + closes [#26](https://code.castopod.org/adaures/castopod/issues/26) +- **api:** add rest api with podcasts read endpoints + ([e64001d](https://code.castopod.org/adaures/castopod/commit/e64001d00604bcf587ec5e9a631282f212df450d)), + closes [#210](https://code.castopod.org/adaures/castopod/issues/210) + +# [1.0.0-beta.15](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2022-06-14) + +### Bug Fixes + +- replace deletedField with published_at for episodes + ([14d7d07](https://code.castopod.org/adaures/castopod/commit/14d7d078225cdc8980759273a5dc4163d9f84b06)) + +### Features + +- add default icons to Alert component + ([0d98001](https://code.castopod.org/adaures/castopod/commit/0d9800123b135e4fa1a2acd14a5e039c12174333)) +- add permanent delete feature for podcasts 🎉 + ([dbb4030](https://code.castopod.org/adaures/castopod/commit/dbb4030da49f9ea1f61759fb7c66d71fc29ea4a1)), + closes [#89](https://code.castopod.org/adaures/castopod/issues/89) +- apply colour theme to embed player + ([9548337](https://code.castopod.org/adaures/castopod/commit/9548337a7c49879e8b58c2dfece46e3cfc9517eb)), + closes [#201](https://code.castopod.org/adaures/castopod/issues/201) +- **episodes:** replace soft delete with permanent delete + ([eb9ff52](https://code.castopod.org/adaures/castopod/commit/eb9ff522c25af8ceb2ed08614b581757ee791d42)) + +# [1.0.0-beta.14](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2022-04-23) + +### Bug Fixes + +- **home:** remove hardcoded prefix in getAllPodcasts query + ([92d5cc5](https://code.castopod.org/adaures/castopod/commit/92d5cc50a3e533875cd894dccc417918102d4b7f)) +- overwrite common lang function to escape returned string + ([4c490c1](https://code.castopod.org/adaures/castopod/commit/4c490c15bb6642ad0b2aaddf08d8af25de99b4b0)), + closes [#196](https://code.castopod.org/adaures/castopod/issues/196) + [#198](https://code.castopod.org/adaures/castopod/issues/198) + +### Features + +- **i18n:** add Spanish to supported locales + ([e340b54](https://code.castopod.org/adaures/castopod/commit/e340b54a84d7dcdf9ba910fe7ff39c453fac0968)) + +# [1.0.0-beta.13](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.12...v1.0.0-beta.13) (2022-04-14) + +### Bug Fixes + +- **rss:** remove escaping for publisher and owner name + ([e2046e4](https://code.castopod.org/adaures/castopod/commit/e2046e4b116ecddb5e6d68487f666b95fd7f493c)) +- use UTC_TIMESTAMP() to get current utc date instead of NOW() in sql queries + ([853a6ba](https://code.castopod.org/adaures/castopod/commit/853a6ba9155b6687604304d59f03d0efb75a9f96)) + +### Features + +- **i18n:** add Norwegian Nynorsk to supported locales + ([744340d](https://code.castopod.org/adaures/castopod/commit/744340df615bee38a54c4abbbb7f03d51b61a39d)) + +# [1.0.0-beta.12](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.11...v1.0.0-beta.12) (2022-04-05) + +### Bug Fixes + +- update form_textarea to prevent escaping value + ([78548b5](https://code.castopod.org/adaures/castopod/commit/78548b5cd75ea7d6688d1945ff5449ea4f6bec68)) + +### Features + +- **i18n:** add support for German and Brazilian Portuguese languages + ([19da003](https://code.castopod.org/adaures/castopod/commit/19da003fd396bff20b89ad330b787e9cdbe8d919)) + +# [1.0.0-beta.11](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2022-04-01) + +### Bug Fixes + +- change message upon cancellation of episode publication + ([9859c74](https://code.castopod.org/adaures/castopod/commit/9859c7434c2a3478ce035f7a4de20f594d63f5b0)) +- prefill description footer input when creating a new episode + ([9ea5ca3](https://code.castopod.org/adaures/castopod/commit/9ea5ca31697c70d176294f8aea37bd57d471fcf7)) +- remove value escaping for form inputs and textareas + ([bc6dea2](https://code.castopod.org/adaures/castopod/commit/bc6dea2f8ad1cf0aee0eaa93151332fbac7fb771)) +- restore default podcast icon on public website + ([342778b](https://code.castopod.org/adaures/castopod/commit/342778bac3c684328d72633961df1a2ebdc1330e)) +- **socialinteract:** move social interact uri into uri attribute + update + social data upon import + ([12b2200](https://code.castopod.org/adaures/castopod/commit/12b22008a237185cb736fc29352fab22421dad16)) + +### Features + +- **analytics-gdpr:** update cached personal data to expire at midnight + ([0188b67](https://code.castopod.org/adaures/castopod/commit/0188b67354a756f0c926edd7b46623ab5b20c12b)) +- **analytics:** add current date and secret salt to analytics hash for improved + privacy + ([6f2e7c0](https://code.castopod.org/adaures/castopod/commit/6f2e7c009c24830d4f08633bfbde3b75f40bf215)) +- **i18n:** add 7 new languages + update german translations + ([d021abb](https://code.castopod.org/adaures/castopod/commit/d021abb52f5525d93810e25df2b453c918d7bc8b)) +- **i18n:** add german language as supported locale + create Language files from + english source + ([c220b31](https://code.castopod.org/adaures/castopod/commit/c220b310ed59cad188af044b1fed0c39efc7da5b)) +- **icons:** add podnews icon to podcasting platforms + ([5f42355](https://code.castopod.org/adaures/castopod/commit/5f423557c2b78fd7c38c5e0caab6c6c80d21e36e)), + closes [#190](https://code.castopod.org/adaures/castopod/issues/190) + +# [1.0.0-beta.10](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2022-03-15) + +### Bug Fixes + +- add explicit int conversion when formatting episode duration + ([1253096](https://code.castopod.org/adaures/castopod/commit/1253096197a0d30692bdafa7152f250cd9a71acf)) +- add href to castopod website on login page + ([cc54257](https://code.castopod.org/adaures/castopod/commit/cc5425735184ad738aa0f38540f18e8971f8f56e)) +- move html escaping on credits page + ([fbffdbd](https://code.castopod.org/adaures/castopod/commit/fbffdbde78544c83138ee6234c62d43056f407b6)) +- remove cache from remote follow form to display error messages + ([90e4443](https://code.castopod.org/adaures/castopod/commit/90e44437bdf37d8024ef609b2f7336dbdfc3b974)) + +### Features + +- add autofocus to input field "Email or username" on login page + ([19caed4](https://code.castopod.org/adaures/castopod/commit/19caed4bce0daab9ccf6ab9645f44b60eb87de88)) +- add WebSub module for pushing feed updates to open hubs + ([10d3f73](https://code.castopod.org/adaures/castopod/commit/10d3f73786ba141e27a822b2585c4a244ee92c14)) +- **GDPR:** add GDPR.yml file to public/.well-known/ + ([86bccc3](https://code.castopod.org/adaures/castopod/commit/86bccc3d5cc9562b89196f1766ac91cdc8ad786d)) + +# [1.0.0-beta.9](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2022-03-04) + +### Bug Fixes + +- **cache:** delete posts and comments pages cache when updating platform links + ([f7c3e5b](https://code.castopod.org/adaures/castopod/commit/f7c3e5bf4ad43389bf8d58d2c4aaf16b81cbce00)), + closes [#169](https://code.castopod.org/adaures/castopod/issues/169) +- escape characters for `min` in format_duration_symbol + ([3b6722a](https://code.castopod.org/adaures/castopod/commit/3b6722a42b9e4330e5235d4ceed41c777159f4dc)) +- **security:** add csrf filter + prevent xss attacks by escaping user input + ([cd2e1e1](https://code.castopod.org/adaures/castopod/commit/cd2e1e1dc37c53d32d00971c451c4800b8fd6107)) +- update ivoox podcasting icon + ([f2b69a4](https://code.castopod.org/adaures/castopod/commit/f2b69a47339c887f57883ec612f3d200e512ac1c)) +- **video-clips:** update condition to check if ffmpeg is installed + ([b57f0b6](https://code.castopod.org/adaures/castopod/commit/b57f0b6eb65dccf22cb4d55f93d18ca36857d7fc)), + closes [#163](https://code.castopod.org/adaures/castopod/issues/163) + +### Features + +- **i18n:** add Polish translation + ([2d83b44](https://code.castopod.org/adaures/castopod/commit/2d83b44add9e4e00766a1f326377ed892f48ad73)) +- **icons:** add default icons for podcasting, social and funding platforms + + remove complex icons + ([5bcdfeb](https://code.castopod.org/adaures/castopod/commit/5bcdfebe6489b5d6b90f3c828b014ec4e9a7e7e1)), + closes [#166](https://code.castopod.org/adaures/castopod/issues/166) + [#167](https://code.castopod.org/adaures/castopod/issues/167) + [#170](https://code.castopod.org/adaures/castopod/issues/170) +- make episode description more visible on episode pages + ([90533be](https://code.castopod.org/adaures/castopod/commit/90533be0298249e5527870c01329fce5f94ec2dc)), + closes [#171](https://code.castopod.org/adaures/castopod/issues/171) +- **podcasting 2.0:** update podcast:social tag to adhere to latest spec + ([a597cf4](https://code.castopod.org/adaures/castopod/commit/a597cf4ecfa6807a3413177d99c816056a7e7c45)) + +# [1.0.0-beta.8](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2022-02-10) + +### Features + +- **podcast-form:** add new_feed_url field to set an url when changing domain or + host + ([e7eec48](https://code.castopod.org/adaures/castopod/commit/e7eec48e7bc06a9aa907db01ed3e5b536e7dd8be)) + +# [1.0.0-beta.7](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2022-02-05) + +### Bug Fixes + +- **activitypub:** allow cors on get requests for routes exposing acitivitypub + objects + ([2f24809](https://code.castopod.org/adaures/castopod/commit/2f2480998f9abb34f02ab186c65d462a74b4e640)) +- **fediverse:** set model instances as non shared to prevent overlapping + ([91128fa](https://code.castopod.org/adaures/castopod/commit/91128fad7a68e1f4e5acacba90b6899288699e61)) +- **htaccess:** add ? after index.php in RewriteRule + ([d9d139e](https://code.castopod.org/adaures/castopod/commit/d9d139eefa03c28d1a064b3b32c9036193497e57)), + closes [#152](https://code.castopod.org/adaures/castopod/issues/152) + +### Features + +- **home:** sort podcasts by recent activity + add dropdown menu to choose + between sorting options + ([7b89da6](https://code.castopod.org/adaures/castopod/commit/7b89da6106c150708782d39ed2742fe416c41e89)), + closes [#164](https://code.castopod.org/adaures/castopod/issues/164) + +# [1.0.0-beta.6](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2022-02-03) + +### Bug Fixes + +- **activitypub:** add conditions for possibly missing actor properties + add + user-agent to requests + ([8fbf948](https://code.castopod.org/adaures/castopod/commit/8fbf948fbba22ffd33966a1b2ccd42e8f7c1f8a2)) +- **activitypub:** add target actor id to like / announce activities to send + directly to note's actor + ([962dd30](https://code.castopod.org/adaures/castopod/commit/962dd305f5d3f6eadc68f400e0e8f953827fe20d)) +- **activitypub:** add target_actor_id for create activity to broadcast post + reply + ([0128a21](https://code.castopod.org/adaures/castopod/commit/0128a21ec55dcc0a2fbf4081dadb4c4737735ba1)) +- **http-signature:** update SIGNATURE_PATTERN allowing signature keys to be + sent in any order + ([b7f285e](https://code.castopod.org/adaures/castopod/commit/b7f285e4e24247fedb94f030356fa6f291f525cc)) +- **install:** set message block on forms to show error messages + ([3a0a20d](https://code.castopod.org/adaures/castopod/commit/3a0a20d59cdae7f166325efb750eaa6e9800ba6e)), + closes [#157](https://code.castopod.org/adaures/castopod/issues/157) +- **markdown-editor:** remove unnecessary buttons for podcast and episode + editors + add extensions + ([9c4f60e](https://code.castopod.org/adaures/castopod/commit/9c4f60e00bcbd4f784f12d2a6fed357ad402ee2e)) +- **podcast-activity:** check if transcript and chapters are set before + including them in audio + ([5855a25](https://code.castopod.org/adaures/castopod/commit/5855a250936f91641efef77650890a18d8e9917f)) +- **podcast:** use markdown description value for editor + set prose class to + about description + ([f304d97](https://code.castopod.org/adaures/castopod/commit/f304d97b14e0ef383509cb3bba50beb55bf701ba)), + closes [#156](https://code.castopod.org/adaures/castopod/issues/156) + +# [1.0.0-beta.5](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2022-01-31) + +### Bug Fixes + +- **analytics:** set initial value for duration and bandwidth + ([ee50539](https://code.castopod.org/adaures/castopod/commit/ee5053959154b1a2e5fbe4b43162968425206a26)) + +# [1.0.0-beta.4](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2022-01-29) + +### Bug Fixes + +- **housekeeping:** replace the use of GLOB_BRACE with looping over file + extensions + ([42d92d0](https://code.castopod.org/adaures/castopod/commit/42d92d0c8dfe0c567c28f5bfdda129890fa4c2ec)), + closes [#154](https://code.castopod.org/adaures/castopod/issues/154) +- **housekeeping:** set default sizes value + ignore illegal IFD size error to + proceed with script + ([f21ca57](https://code.castopod.org/adaures/castopod/commit/f21ca57603cfa503699b7e09a155e18d876d65fe)) + +### Features + +- **housekeeping:** add clear_cache option to flush redis or files cache + ([99bfac0](https://code.castopod.org/adaures/castopod/commit/99bfac0b428a4bc6fe8bfd10a355dfd93f42ba5c)) + +# [1.0.0-beta.3](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2022-01-28) + +### Bug Fixes + +- revert to beta.1's codeigniter4 version + ([e831411](https://code.castopod.org/adaures/castopod/commit/e83141127080ccde44987195db46ba97fd6cc2ca)) + +# [1.0.0-beta.2](https://code.castopod.org/adaures/castopod/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2022-01-28) + +### Bug Fixes + +- **migrations:** ignore invalid utf8 chars for media files metadata + update + transcript parser + ([45e8f99](https://code.castopod.org/adaures/castopod/commit/45e8f99e753cc02ec105e6f4d7fe026a205724f8)) +- **video-clips:** set audio codec to aac, fixing audio issue on twitter + ([3c22c68](https://code.castopod.org/adaures/castopod/commit/3c22c68ee81f77bd7fcf7e2739ee6af016407843)) +- **video-clips:** set longer podcast and episode lengths for squared format + ([c030113](https://code.castopod.org/adaures/castopod/commit/c0301134c2048dc29eb2b995e4d5c22c49444100)) + +# 1.0.0-beta.1 (2022-01-23) + +### Bug Fixes + +- **a11y:** replace active tab color to contrast with background on podcast and + episode pages + ([f3785e1](https://code.castopod.org/adaures/castopod/commit/f3785e140147d085a2fb6a62ded87cdfe360f442)) +- **activity-pub:** cache issues when navigating to activity stream urls + ([7bcbfb3](https://code.castopod.org/adaures/castopod/commit/7bcbfb32f7cca08d111be46c7f1640e372d4a4b0)) +- **activity-pub:** get database records using new model instances + ([92536dd](https://code.castopod.org/adaures/castopod/commit/92536ddb3812214a9c5682b92e547e5c1998a5d7)) +- **activitypub:** set created_by to null for reblog if no user + update episode + oembed data + ([209dfbd](https://code.castopod.org/adaures/castopod/commit/209dfbd134e1a2cc02e7c24c158d786fa4dda61d)) +- add admin-audio-player to vite config to have admin player show up + ([93cb9b2](https://code.castopod.org/adaures/castopod/commit/93cb9b24701c09b92820204a67c1fc1b3c044708)) +- add application/octet-stream mimetype to mp3 and m4a extensions to prevent + ext_in error + ([339bef8](https://code.castopod.org/adaures/castopod/commit/339bef878e54983d86e91e6ff7a931a843d321b3)), + closes [#145](https://code.castopod.org/adaures/castopod/issues/145) +- add category_label component to include parent category in about podcast page + ([74e7d68](https://code.castopod.org/adaures/castopod/commit/74e7d68ac834885c4b89ee6e7d60db2157165799)) +- add head request to analytics_hit route + ([f0a2f0b](https://code.castopod.org/adaures/castopod/commit/f0a2f0bea491ca91976b351bb79837e95c9d094b)) +- add missing explicit badge for podcasts and episodes + ([cdf9f9d](https://code.castopod.org/adaures/castopod/commit/cdf9f9d53f2597f19455cb65c51da4677bb99327)) +- add open graph size for podcast images to replace the inadequate large format + ([33aae1f](https://code.castopod.org/adaures/castopod/commit/33aae1f7934e4962116e94e477dbf48e24971f5f)) +- add public/media folder to castopod bundle + ([8053d35](https://code.castopod.org/adaures/castopod/commit/8053d3521b481872711dabaaf265d08b9bfbaa87)), + closes [#52](https://code.castopod.org/adaures/castopod/issues/52) +- add translation key for audio-clipper trim labels + ([db191ac](https://code.castopod.org/adaures/castopod/commit/db191ac31bd16bad2a72afdb8b25c685adf86a6e)) +- add where condition to get episode count without deleted episodes + ([7661734](https://code.castopod.org/adaures/castopod/commit/7661734ed296654630f3668132671117519145dd)), + closes [#67](https://code.castopod.org/adaures/castopod/issues/67) +- **admin:** save block and lock switches + ([b66c0af](https://code.castopod.org/adaures/castopod/commit/b66c0afc8fab2e338402a9a4f8105e5f5459e208)) +- **analytics:** redirect to mp3 file even when referer was not set + ([9fc388d](https://code.castopod.org/adaures/castopod/commit/9fc388d154f29c335dedcd624abe8c1751762c07)) +- **analytics:** remove charts empty values + remove useless language cache + ([1678794](https://code.castopod.org/adaures/castopod/commit/16787941539ba4014281a366789ea896a9cd2afc)) +- **analytics:** set duration field to precise decimal as episode's audio file + duration + ([d772685](https://code.castopod.org/adaures/castopod/commit/d77268540569b2be9d91d5e09aefb3ff5ac2b071)) +- **analytics:** update migrations to set decimal precision for latitude and + longitude + ([714d6b5](https://code.castopod.org/adaures/castopod/commit/714d6b5d4950e52cf1c3170bb59954f98ffd48bd)) +- **analytics:** update service management so that it works with new OPAWG slug + values + ([7fe9d42](https://code.castopod.org/adaures/castopod/commit/7fe9d42500ade2c6fa3ff4365b4affc475af0e51)) +- **audio-clipper:** add mouse position offset when stretching clip to prevent + content from jumping + ([602654b](https://code.castopod.org/adaures/castopod/commit/602654b99b33ee8c29da080058a0aaea976cd484)) +- **audio-clipper:** show audio playing progress + put waveform behind audio + clipper + ([01a09dc](https://code.castopod.org/adaures/castopod/commit/01a09dc447b81c5412ceb45d6706a867939fd4dd)) +- **avatar:** use default avatar when no avatar url has been set + ([9d23c7e](https://code.castopod.org/adaures/castopod/commit/9d23c7e7e142c6cf1a1418e37e41d711064593c4)), + closes [#111](https://code.castopod.org/adaures/castopod/issues/111) +- **bundle:** include modules and themes when copying files with rsync + ([cd5bb88](https://code.castopod.org/adaures/castopod/commit/cd5bb8835c6e259408a8c13a2196a347e161da83)) +- **bundle:** update vite input files path + add `set -e` in bash scripts to + fail if command fails + ([0ee53c7](https://code.castopod.org/adaures/castopod/commit/0ee53c71ffadb8a6ddb1febd9f912bc99f5f7a0b)) +- **cache:** add locale for podcast and episode pages + clear some persisting + cache in models + ([9cec8a8](https://code.castopod.org/adaures/castopod/commit/9cec8a81ccbb7239402fe6633dbc31979272302a)), + closes [#42](https://code.castopod.org/adaures/castopod/issues/42) + [#61](https://code.castopod.org/adaures/castopod/issues/61) +- **cache:** return a non cached view when connected + ([e2e7358](https://code.castopod.org/adaures/castopod/commit/e2e735815d805a48eed2ea3288d060d0ddb253a3)) +- **cache:** suffix cache names with authenticated for credits, map and pages + ([418a70b](https://code.castopod.org/adaures/castopod/commit/418a70b2a670d8ba0ab6c15fa5faa41f6be55e53)) +- cast actor_id to pass as int to set_interact_as_actor() function + ([56a8e5d](https://code.castopod.org/adaures/castopod/commit/56a8e5d7dd615322aeb007e730801c65d0b02e5c)) +- **category:** remove uncategorized option to enforce users in choosing a + category + ([8c64f25](https://code.castopod.org/adaures/castopod/commit/8c64f25a0e72fec03d25544797d32623b2276fce)) +- check for database connection and podcasts table existence before redirecting + to install + ([eb74e81](https://code.castopod.org/adaures/castopod/commit/eb74e81c3d93581e310b391cd029e62a0d690a8a)) +- check that additional files are valid when creating episode + ([eac5bc8](https://code.castopod.org/adaures/castopod/commit/eac5bc876de125e1fe08d1b89f767a04fc0fbfb6)) +- check that note has a preview_card_id before displaying it + ([acb8b3a](https://code.castopod.org/adaures/castopod/commit/acb8b3a40172ccb184ffe544760601d756692e6c)), + closes [#114](https://code.castopod.org/adaures/castopod/issues/114) +- clear cache when deleting podcast banner + ([99bb40b](https://code.castopod.org/adaures/castopod/commit/99bb40b8bc17b8ee2cd8468a82e46ea280c92cb6)) +- comment all cache clean after page update to prevent analytics cache deletion + ([e6197a4](https://code.castopod.org/adaures/castopod/commit/e6197a4972a3cce3d67dd7972bb54f8720b8e5b7)) +- **comments:** add comment view partials for public pages + ([fcecbe1](https://code.castopod.org/adaures/castopod/commit/fcecbe1c68b0d28d19454fba65caf3ab769fbc75)) +- correct chart data + ([4d3e9c8](https://code.castopod.org/adaures/castopod/commit/4d3e9c8c02cdc882e9fe1c29625695b6f83c820a)) +- correct percona compatibility issue + ([e53f819](https://code.castopod.org/adaures/castopod/commit/e53f819264b2d6902996f11ffcbb7c99295a90ef)) +- correct php-fpm issues + ([1ef55d7](https://code.castopod.org/adaures/castopod/commit/1ef55d7315bb44abe05f02ec8a84b6b6a557a9a0)) +- correct referrer bug + ([ed69b2f](https://code.castopod.org/adaures/castopod/commit/ed69b2f5004ed1cd18bac824c08a0df01f5d2637)) +- correction for servers with low int precision + ([31b7828](https://code.castopod.org/adaures/castopod/commit/31b7828e77519ef43e9bcfcbdf6c21712f97a571)) +- **cors:** add preflight option routes for episode, podcast and status objects + ([a281abf](https://code.castopod.org/adaures/castopod/commit/a281abfda475388a07943c169dab460cc2d4f944)) +- declare typed properties in PHPDoc for php<7.4 + ([14dd44d](https://code.castopod.org/adaures/castopod/commit/14dd44d03d6db0d9ae4198db8e65c92a0e45cb31)), + closes [#23](https://code.castopod.org/adaures/castopod/issues/23) +- define podcast_id and platform_slug as foreign keys in podcasts_plaforms table + ([6e9451a](https://code.castopod.org/adaures/castopod/commit/6e9451a1103b43750fa70ad576de36af25ca29cb)) +- define podcastNamespaceLink value + ([0d744d2](https://code.castopod.org/adaures/castopod/commit/0d744d212df0d070ceea185068eaf2746e1ccd48)) +- **embeddable-player:** enable any ancestor when X-Frame-Options is set on + server + ([44a4962](https://code.castopod.org/adaures/castopod/commit/44a4962e0b7e3ed87e9914b4e7792a0d52330ff8)) +- **embed:** open embedded player's links in new tab + ([4aa73d7](https://code.castopod.org/adaures/castopod/commit/4aa73d71e3b8c0a6c3f75f4d1d45c4d693aba64c)) +- **episode-form:** show warning to set `memory_limit`, `upload_max_filesize` & + `post_max_size` + ([3b3c218](https://code.castopod.org/adaures/castopod/commit/3b3c218b9c868e9f12c54d7670e69d84c9ee79c0)), + closes [#5](https://code.castopod.org/adaures/castopod/issues/5) + [#86](https://code.castopod.org/adaures/castopod/issues/86) +- **episodeCount:** add missing brackets to French language file + ([c1b4112](https://code.castopod.org/adaures/castopod/commit/c1b411265ad9b06e95a8b097ecf73445b88dcb45)) +- **episode:** replace guid's empty string value to null + ([441052a](https://code.castopod.org/adaures/castopod/commit/441052af8d99e6e317edefd1e58ad71799357088)) +- **episodes-page:** handle defaultQuery being null when no podcast episodes + ([15183b7](https://code.castopod.org/adaures/castopod/commit/15183b7eab57dac007bcdfa8c3651239de1ae05a)), + closes [#100](https://code.castopod.org/adaures/castopod/issues/100) +- **episodes-table:** set descriptions to be not null + ([6774ec1](https://code.castopod.org/adaures/castopod/commit/6774ec10fa78527be6b7548ca1dc34ad0ada090c)) +- **episodes:** add publication status + set publication date to null when none + has been set + ([d882981](https://code.castopod.org/adaures/castopod/commit/d882981b3a86c81921ce6b07d4cf61fc13983689)), + closes [#70](https://code.castopod.org/adaures/castopod/issues/70) +- escape generated feed tag values and remove new lines from public pages meta + description + ([6238a43](https://code.castopod.org/adaures/castopod/commit/6238a43863210afe8988ad7cf251e6bfc6c8557c)), + closes [#57](https://code.castopod.org/adaures/castopod/issues/57) + [#46](https://code.castopod.org/adaures/castopod/issues/46) +- expire default query cache upon scheduled episode publication + ([b72e7c8](https://code.castopod.org/adaures/castopod/commit/b72e7c8691c887e41107baea0a4d50a39eaf8c8b)), + closes [#81](https://code.castopod.org/adaures/castopod/issues/81) +- fix layout bugs in admin and update translation files + ([a834171](https://code.castopod.org/adaures/castopod/commit/a83417180cf61cdfadc5509b0aaa2fdb66592be3)), + closes [#40](https://code.castopod.org/adaures/castopod/issues/40) +- **follow:** add missing helpers to Actor controller + ([ee53a73](https://code.castopod.org/adaures/castopod/commit/ee53a732dc12ebbf5706e14969749a12cfd9d559)) +- handle HEAD requests on podcast_feed route + ([74b2640](https://code.castopod.org/adaures/castopod/commit/74b2640f2a25c4cd6fd8835fc492c2a6893d4950)), + closes [#79](https://code.castopod.org/adaures/castopod/issues/79) +- **images:** set default mimetype if none is specified when getting size info + ([6e4acc6](https://code.castopod.org/adaures/castopod/commit/6e4acc64ad256178cee7905402b48bafcd49f84c)) +- **import-with-escaped-characters:** remove \CodeIgniter\HTTP\URI in + download_file, closes + [#103](https://code.castopod.org/adaures/castopod/issues/103) + ([35b5be0](https://code.castopod.org/adaures/castopod/commit/35b5be095ff54d27acec1610a846ec0cdbdf1d65)) +- **import:** add extension when downloading file without + truncate slug if too + long + ([c5f18bb](https://code.castopod.org/adaures/castopod/commit/c5f18bb6dc08a758ff735454bbe9cfa45a68c09b)) +- **import:** add validation for handle field to prevent + Router.invalidParameterType error + ([5bf7200](https://code.castopod.org/adaures/castopod/commit/5bf7200fb390f2447b29f24b495f24483cf7b205)), + closes [#119](https://code.castopod.org/adaures/castopod/issues/119) +- **import:** cast description's SimpleXMLElement to string + ([02d17be](https://code.castopod.org/adaures/castopod/commit/02d17be4ffe229fc6657207d31eba0543b5f1a4c)) +- **import:** remove query string from files url + ([109c4aa](https://code.castopod.org/adaures/castopod/commit/109c4aa1afb72dd8b99c0302d74a7fef5a38638e)) +- **import:** save media files during podcast import + set missing media fields + ([a9989d8](https://code.castopod.org/adaures/castopod/commit/a9989d841a634f8cf6c04df25f40bb1e7d4fcdcc)) +- **import:** set episode and season numbers to null when not present in item + tag + ([3211398](https://code.castopod.org/adaures/castopod/commit/3211398c78b1b28b76a46427ee07874bbf84a85d)) +- **import:** use tag when no is present + ([20e607a](https://code.castopod.org/adaures/castopod/commit/20e607afb755bc75056041738fa7cbf6723d754c)) +- include missing variables on public ui's episode page and remote_actions + ([193b373](https://code.castopod.org/adaures/castopod/commit/193b373bc94a5270acae99b637aa84b6cb2dedfe)) +- **install:** redirect manually to install wizard on first visit + ([2ceaaca](https://code.castopod.org/adaures/castopod/commit/2ceaaca44f1b82fc64d961e2fb4f4aaeade7e736)) +- **install:** redirect to host_url install route on instanceConfig validation + error + ([99250b1](https://code.castopod.org/adaures/castopod/commit/99250b1868657c249a447399c7ebc69e00d43d1a)) +- **install:** redirect to input baseUrl after instance config + ([2426af7](https://code.castopod.org/adaures/castopod/commit/2426af7de8c9d426aaf534ff17b67f71c2e9f374)), + closes [#53](https://code.castopod.org/adaures/castopod/issues/53) +- **interact-as:** set actor_id instead of podcast id upon login event + ([5dfade7](https://code.castopod.org/adaures/castopod/commit/5dfade7cf37f339c56d2e577c679b88a1b1d9336)), + closes [#104](https://code.castopod.org/adaures/castopod/issues/104) +- **json-ld:** add missing properties to PodcastSeries object + ([e97266c](https://code.castopod.org/adaures/castopod/commit/e97266c5d4883a10f68b3685ecc0d1942f54d658)) +- keep subtitle line breaks when parsing srt file to json + ([cfb3da6](https://code.castopod.org/adaures/castopod/commit/cfb3da6592f2de23cb1a7ac420f19fc77fa338aa)) +- **layouts:** replace holy-grail layout with tailwind config + widen public + podcast layout + ([be5a287](https://code.castopod.org/adaures/castopod/commit/be5a28787fdb180b64d9bf570120eff7072ab9aa)) +- **map:** update episode markers query to discard unpublished episodes + ([b3caac4](https://code.castopod.org/adaures/castopod/commit/b3caac45b12a23e4289d00133d2ad7915d084c44)) +- **md-editor:** build new markdown editor with lit + + github/markdown-toolbar-element + ([9ec1cb9](https://code.castopod.org/adaures/castopod/commit/9ec1cb93da6f41124c48b8cf14ee6942e865bede)), + closes [#93](https://code.castopod.org/adaures/castopod/issues/93) + [#94](https://code.castopod.org/adaures/castopod/issues/94) + [#120](https://code.castopod.org/adaures/castopod/issues/120) +- minor corrections + ([13be386](https://code.castopod.org/adaures/castopod/commit/13be386842e94d9def1f7de4720931d8f6935171)) +- move analytics to helper + ([d311917](https://code.castopod.org/adaures/castopod/commit/d31191732e41aa106234b5ebe6e54ee02f0ce603)) +- **multiselect:** add missing class names in choices options for purge to work + properly + ([719538d](https://code.castopod.org/adaures/castopod/commit/719538d0ccb28af3c3c5e1a4b6468d4b772fe819)) +- **open-graph:** replace non existant episode description to podcast + description in podcast page + ([b02584e](https://code.castopod.org/adaures/castopod/commit/b02584ee609af1ad1b5680cc28208d113eb0410b)) +- **package.json:** update destination of postcss generation scripts + ([21413f8](https://code.castopod.org/adaures/castopod/commit/21413f8af3b8a0ac01d8c6f15bcd7a63e524e964)) +- **pages:** add locale to page cache + ([8f999ce](https://code.castopod.org/adaures/castopod/commit/8f999ce2f7ee1416c30cf58c84f67b3d11b3f142)) +- **partner:** set correct image URL + ([61554be](https://code.castopod.org/adaures/castopod/commit/61554be12a64d59ab99fab810b1b05632b408f3a)) +- pass timezone to relative time component to show the localized time in the UI + ([b9db936](https://code.castopod.org/adaures/castopod/commit/b9db936461d4cb914958bb3256bb910bbd7ba815)) +- **persons:** prevent overflow of persons list by adding horizontal scroll + ([9e8995d](https://code.castopod.org/adaures/castopod/commit/9e8995dc6e039032cc65f87895cf770f99e8b244)) +- **persons:** set person picture as optional for better ux + ([7fdea63](https://code.castopod.org/adaures/castopod/commit/7fdea63de7e572810082c84fff3013af580df58b)), + closes [#125](https://code.castopod.org/adaures/castopod/issues/125) +- **platforms:** display platform link only when visible is toggled on + ([6e503c8](https://code.castopod.org/adaures/castopod/commit/6e503c8d6182987e48892370623183f871bbd1c1)), + closes [#39](https://code.castopod.org/adaures/castopod/issues/39) +- **podcast-import:** move guid attribute declaration for Episode entity to + include slug data + ([5d02ae3](https://code.castopod.org/adaures/castopod/commit/5d02ae39908a9d743627135b372bf981134c4328)) +- **pwa:** add scope to webmanifests to allow installing an app per podcast + ([74c683e](https://code.castopod.org/adaures/castopod/commit/74c683eb44398a84443ec17903c3e002bb5ea9b9)) +- **pwa:** set app display as standalone in the webmanifests + ([7aa37d2](https://code.castopod.org/adaures/castopod/commit/7aa37d24ac13a1ee160c01a56b43621d7efcfbbc)) +- re-order graph values + ([35f633b](https://code.castopod.org/adaures/castopod/commit/35f633b4c71c087d1ddc9bba9e9bbe18de09204f)) +- redirect to non cached views when authenticated in public views + ([482b47b](https://code.castopod.org/adaures/castopod/commit/482b47ba6bdab7f27fc5704a559567228e07cd14)) +- **release:** add missing version number to castopod-host package + ([8f3e9d9](https://code.castopod.org/adaures/castopod/commit/8f3e9d90c14545d3f84d4469b26a53db4554b4dc)) +- remove defer from js script declaration as it is a module + ([18ae557](https://code.castopod.org/adaures/castopod/commit/18ae557e97f1cef775cd1e75fb1fedee7f1c0cc9)) +- remove fixed size from podcast sidebar + rearrange account info + space out + import radio inputs + ([776eec6](https://code.castopod.org/adaures/castopod/commit/776eec6f0d533d6c92ebec16f7a9dbfcde1f41f4)) +- remove required for other_categories field and add podcast_id to latest + podcasts query + ([5417be0](https://code.castopod.org/adaures/castopod/commit/5417be0049288489a19c7b575aa77bd1e2bc0243)) +- remove required property to persons picture + ([c546be3](https://code.castopod.org/adaures/castopod/commit/c546be385b243014243ae93356006cd126d2f00d)), + closes [#125](https://code.castopod.org/adaures/castopod/issues/125) +- rename field status to task_status to get scheduled activities + ([4ff82a5](https://code.castopod.org/adaures/castopod/commit/4ff82a5f0a38dbbc9e272fca7df70ea5a190e334)) +- rename issue_templates labels + ([9f00305](https://code.castopod.org/adaures/castopod/commit/9f00305844e5a168e89d727fe29892b4ad5e48d6)) +- rename MyAccount controller file + ([e109df3](https://code.castopod.org/adaures/castopod/commit/e109df3004a3a98d72de39532e062fff9917f50f)), + closes [#60](https://code.castopod.org/adaures/castopod/issues/60) +- rename podcast name to podcast handle to clarify field usage + ([9dd4c77](https://code.castopod.org/adaures/castopod/commit/9dd4c7741eb1b7cb5fc214ff674697f3aa986df0)), + closes [#126](https://code.castopod.org/adaures/castopod/issues/126) +- reorder fields as composite primary keys for analytics tables + ([9660aa9](https://code.castopod.org/adaures/castopod/commit/9660aa97c8ffd4fe61f3a388d52b9ac5dd8e1d63)) +- replace getWebEnclosureUrl with getEnclosureWebUrl + ([8122cea](https://code.castopod.org/adaures/castopod/commit/8122ceaf8a70050f14b3078f28b024e7d7cdb9ac)) +- replace hardcoded style links with vite service + set default value for remote + transcript url + ([3f2e056](https://code.castopod.org/adaures/castopod/commit/3f2e05608e43d47bbb518a9acfaf56ec3eefafb4)), + closes [#149](https://code.castopod.org/adaures/castopod/issues/149) + [#150](https://code.castopod.org/adaures/castopod/issues/150) +- replace website key for webpages in breadcrumb translate file + ([50e32ff](https://code.castopod.org/adaures/castopod/commit/50e32ff75636c1d4c5d945a267e884cb26ad7191)) +- rewrite regenerate image function to use saveSizes method from Image entity + ([3889912](https://code.castopod.org/adaures/castopod/commit/38899124ec27e94a8c798bc2db528f9f785eec20)) +- **rss-import:** add Castopod user-agent, handle redirects for downloaded + files, add Content namespace + ([214243b](https://code.castopod.org/adaures/castopod/commit/214243b3fec4937e45ef1ceaba1149004cdf3b44)) +- **rss:** cast number type values to string in rss_helper + ([7180ae9](https://code.castopod.org/adaures/castopod/commit/7180ae9ec700930b69c04ed91f8eceea16ad77ce)), + closes [#148](https://code.castopod.org/adaures/castopod/issues/148) +- **rss:** do not escape podcast and episode titles in the xml + ([0dd3b7e](https://code.castopod.org/adaures/castopod/commit/0dd3b7e0bf00d5a9eb80c93cba1efcada59ec3c1)), + closes [#138](https://code.castopod.org/adaures/castopod/issues/138) + [#71](https://code.castopod.org/adaures/castopod/issues/71) +- **rss:** set ❬itunes:author❭ tag to owner_name if publisher not specified + ([2271c14](https://code.castopod.org/adaures/castopod/commit/2271c1445b1ded12bc53b5d23b5e59d12b17c71a)), + closes [#96](https://code.castopod.org/adaures/castopod/issues/96) +- **rss:** use originalPath instead of originalMediaPath in Image library + ([b4012b7](https://code.castopod.org/adaures/castopod/commit/b4012b7d2ed6b34b69ad767570dd33f0dc7db920)) +- save transcript and chapters files to podcasts folder + ([63f49c7](https://code.castopod.org/adaures/castopod/commit/63f49c719f672b615c5a8893d3868dffcd332e47)) +- set cache expiration to next note publish to show note on publication date + ([0a66de3](https://code.castopod.org/adaures/castopod/commit/0a66de3e6c17d4ac94ee8e13bd00ceaf64b1303e)) +- set episode description footer to null when empty value + ([3a7d97d](https://code.castopod.org/adaures/castopod/commit/3a7d97d660046d80698611311ff3708110d2af82)) +- set episode duration translation to hardcoded english + ([c39efc9](https://code.castopod.org/adaures/castopod/commit/c39efc9489180662edcebd142d4476c0617ea97f)), + closes [#64](https://code.castopod.org/adaures/castopod/issues/64) +- set episode guid upon episode creation + ([ad8b153](https://code.castopod.org/adaures/castopod/commit/ad8b153f2a3b1a3b1751bf63785c4950e1516e6b)), + closes [#48](https://code.castopod.org/adaures/castopod/issues/48) +- set episode numbers during import + remove all custom form_helpers + minor ui + issues + ([99a3b8d](https://code.castopod.org/adaures/castopod/commit/99a3b8d33e00482da50dd62bdaa9215a351a56e4)) +- set localized slug_field key as string in french language + ([17fb29b](https://code.castopod.org/adaures/castopod/commit/17fb29b20993b7deee4e252e0e3a4a2459ee0d98)) +- set location to null when getting empty string + ([71b1b5f](https://code.castopod.org/adaures/castopod/commit/71b1b5f775af475b1dc78328330e277f565e41b6)) +- **settings:** add .jpg extension to site-icon file input to display all jpeg + images + ([f611a16](https://code.castopod.org/adaures/castopod/commit/f611a16cd0c1a389e1c5a287eaec9d2a927a4bb6)) +- sort episodic podcasts by season + ([d7b6794](https://code.castopod.org/adaures/castopod/commit/d7b6794f68f9a01fd606a407c6eb4c12d15dee74)) +- **themes:** update themes stylesheet route and remove css extension + ([e4e7e00](https://code.castopod.org/adaures/castopod/commit/e4e7e0005e931967dd6162588f1c5913dbf4603e)) +- **types:** update fake seeders types + fix bugs + ([76a4bf3](https://code.castopod.org/adaures/castopod/commit/76a4bf344160df679db29e236e7df7822970fb60)) +- unpublish episode before deleting it + add validation step before deletion + ([f75bd76](https://code.castopod.org/adaures/castopod/commit/f75bd76458eeb01a2d37912695e33f77d03b7a69)), + closes [#112](https://code.castopod.org/adaures/castopod/issues/112) + [#55](https://code.castopod.org/adaures/castopod/issues/55) +- update .htaccess for shared hosting config + ([2379826](https://code.castopod.org/adaures/castopod/commit/2379826352e2f4b5060910bf9f29268610102f2e)) +- update broken contributor dropdown fields + ([e5b7515](https://code.castopod.org/adaures/castopod/commit/e5b75150234bd7f19e01def93425d3bda7379dd3)) +- update condition in AnalyticsTrait + ([fbc0967](https://code.castopod.org/adaures/castopod/commit/fbc0967caa81630d514ddb1b93b0834ebb4d913b)) +- update condition in home controller to redirect to install page + ([33f1b91](https://code.castopod.org/adaures/castopod/commit/33f1b91d55dd0652c979d50fc85879dbf88a4a42)) +- update conditions when checking for empty max_episodes and season_number + ([fbad0b5](https://code.castopod.org/adaures/castopod/commit/fbad0b59f68c65eba2fdcd5a8d3b312b622e9a45)) +- update iso-369 language table seeder + ([0c90db4](https://code.castopod.org/adaures/castopod/commit/0c90db44c40de5af5b0b32b54489bda9424d9ef6)) +- update MarkdownEditor component + restyle Button and other components + ([b05d177](https://code.castopod.org/adaures/castopod/commit/b05d177f1b7f44fef043ac5eb41f07133a2cf52d)) +- update purgecss content path for php helper files + ([eb70bb4](https://code.castopod.org/adaures/castopod/commit/eb70bb4f7078ff347aeb8f5dcc7896311d289466)), + closes [#59](https://code.castopod.org/adaures/castopod/issues/59) +- update translations for settings' tasks to include what they should be used + for + ([06b1a8b](https://code.castopod.org/adaures/castopod/commit/06b1a8b29b6ce5d81c5570d250bdac4e0c9ee5ca)) +- use slash instead of backslash to call layout + ([a80adb2](https://code.castopod.org/adaures/castopod/commit/a80adb22958fc0a38374cbce2d950a0042e699eb)) +- **ux:** allow for empty message upon episode publication and warn user on + submit + ([33d01b8](https://code.castopod.org/adaures/castopod/commit/33d01b8d4fd6ebf24e9f011aa705c456c846956c)), + closes [#129](https://code.castopod.org/adaures/castopod/issues/129) +- **ux:** redirect user to install page on database error in home page + ([9017e30](https://code.castopod.org/adaures/castopod/commit/9017e30bf41bed8c2be65091bbc5fb1e63aef87a)) +- **video-clips:** check if created video exists before recreating it and + failing + ([dff1208](https://code.castopod.org/adaures/castopod/commit/dff12087251b2b89e195604202094b5ddd9a0936)) +- **video-clips:** clear video clip cache after process has finished + ([3ae6232](https://code.castopod.org/adaures/castopod/commit/3ae62325856f6ff331a5d9ed901b9fa097ca7055)) +- **video-clips:** create unique temporary files for resources to be deleted + after generation + ([7f7c878](https://code.castopod.org/adaures/castopod/commit/7f7c878cb6ecf7b4a967b2af87da82bc6593081e)) +- **video-clips:** tweak portrait parameters to have subtitles display without + overflowing + ([2385b1a](https://code.castopod.org/adaures/castopod/commit/2385b1a2926d1344569836e18cb30adb4c604664)) +- **xml-editor:** escape xml editor's content + restyle form sections to prevent + overflowing + ([588590b](https://code.castopod.org/adaures/castopod/commit/588590bd2c0346e2465ff8f1930580d76a3bf068)) + +### Features + +- **activitypub:** add Podcast actor and PodcastEpisode object with comments + ([9e1e5d2](https://code.castopod.org/adaures/castopod/commit/9e1e5d2e862d6a3345d11ca7f96b955c76bfa013)) +- add alternate rss feed link tag to podcast page head + ([a973c09](https://code.castopod.org/adaures/castopod/commit/a973c097d54a3d0186c4079b9d4d3e81aae38505)), + closes [#35](https://code.castopod.org/adaures/castopod/issues/35) +- add analytics and unknown useragents + ([ec92e65](https://code.castopod.org/adaures/castopod/commit/ec92e65aa42e09b1df04600b52a0c679dfc494bb)) +- add audio-clipper toolbar + add video-clip-previewer + ([0255753](https://code.castopod.org/adaures/castopod/commit/02557539e6eb48fc23ee2ee3b0c75aee3310965b)) +- add audio-clipper webcomponent (wip) + ([21d4251](https://code.castopod.org/adaures/castopod/commit/21d4251b9bcd5acb0f8a1761bc4edc34a3dbc228)) +- add basic stats on podcast about page + ([1670558](https://code.castopod.org/adaures/castopod/commit/1670558473dba47219d470ff21d6224db6ab42ba)) +- add breadcrumb in admin area + ([7fb1de2](https://code.castopod.org/adaures/castopod/commit/7fb1de2cf3c97c4cd7afe3bd71bbe66041786ecd)), + closes [#17](https://code.castopod.org/adaures/castopod/issues/17) +- add cache to ActivityPub sql queries + cache activity and note pages + ([2d297f4](https://code.castopod.org/adaures/castopod/commit/2d297f45b3d7ef6e8711875a0b9b908e878115fa)) +- add CDN url + ([972bcbf](https://code.castopod.org/adaures/castopod/commit/972bcbf65ee119b8641ca3c4e5c0e8cf9ca8dd4f)), + closes [#37](https://code.castopod.org/adaures/castopod/issues/37) +- add codemirror to display xml editor for custom rss field + ([f15f262](https://code.castopod.org/adaures/castopod/commit/f15f26240cd5311fa9d07779f364b6639a501dec)) +- add cumulative listening time charts + ([588b4d2](https://code.castopod.org/adaures/castopod/commit/588b4d28da00bc12d02126e23181690f54d81716)) +- add DropdownMenu component + remove global audio player in admin + ([abb7fba](https://code.castopod.org/adaures/castopod/commit/abb7fbac276d77b7d31a0aeba75d464f3ba3ad46)) +- add episode_numbering() component helper to display episode and season numbers + ([3f4a6bd](https://code.castopod.org/adaures/castopod/commit/3f4a6bd0b9f870f16107a41b102b6bf734868198)) +- add french translation + ([196920d](https://code.castopod.org/adaures/castopod/commit/196920d62f1810b4c35f800d17d7f93627319091)) +- add heading component + update ecs rules to fix views + ([23bdc6f](https://code.castopod.org/adaures/castopod/commit/23bdc6f8e36b7e8dfbe32755a54dea59ad913432)) +- add housekeeping task to run after migrations + ([89dee41](https://code.castopod.org/adaures/castopod/commit/89dee41d583e57251ea9315402a757f03571d7ad)) +- add install wizard form to bootstrap database and create the first superadmin + user + ([cba871c](https://code.castopod.org/adaures/castopod/commit/cba871c5df9f7120c44d9952456ebbd0d220669e)), + closes [#2](https://code.castopod.org/adaures/castopod/issues/2) +- add ISO 3166 country codes + ([97cd94b](https://code.castopod.org/adaures/castopod/commit/97cd94b47494b66faf43fbbe0748872da80020a4)) +- add js audio player on podcast, admin and embeddable player pages + fix admon + episodes ux + ([0e14eb4](https://code.castopod.org/adaures/castopod/commit/0e14eb4d3f526b0fd256a6144f3fbfc3fe52a357)), + closes [#131](https://code.castopod.org/adaures/castopod/issues/131) +- add lock podcast according to the Podcastindex podcast-namespace to prevent + unauthozized import + ([72b3012](https://code.castopod.org/adaures/castopod/commit/72b301272e0b70ded3e2b237391909e3f152ad0b)) +- add map analytics, add episodes analytics, clean analytics page layout, + translate countries + ([07eae83](https://code.castopod.org/adaures/castopod/commit/07eae83a00d860e149359fae67d549488403d88b)) +- add media entity and link documents, images and audio files to it + ([6ecf286](https://code.castopod.org/adaures/castopod/commit/6ecf2866cfcde31a0840f15c3340808ce14b44cf)) +- add Noto Sans Mono font to use for durations + button to access new video clip + form in list + ([7609bb6](https://code.castopod.org/adaures/castopod/commit/7609bb60330539aa91bfdafbb35c2d585624218a)) +- add npm for js dependencies + move src/ files to root folder + ([cbb83a6](https://code.castopod.org/adaures/castopod/commit/cbb83a6f308ac9357e9fb0cca5edae9d3fee5b48)) +- add Open Graph and Twitter meta tags + ([af970b8](https://code.castopod.org/adaures/castopod/commit/af970b8bac949e4c63047e04aca1b7403a4e8deb)), + closes [#41](https://code.castopod.org/adaures/castopod/issues/41) +- add pages table to store custom instance pages (eg. legal-notice, cookie + policy, etc.) + ([9c224a8](https://code.castopod.org/adaures/castopod/commit/9c224a8ac6dd95f3c6c087a300fc8bac48e8090f)), + closes [#24](https://code.castopod.org/adaures/castopod/issues/24) +- add platform models + ([a333d29](https://code.castopod.org/adaures/castopod/commit/a333d291966229a909c0851fd8b890ed97c48ceb)) +- add platforms form in podcast settings + ([043f49c](https://code.castopod.org/adaures/castopod/commit/043f49c784bc007ca0fa756ca4ed2d3b08843ad9)) +- add platforms tables + ([ce59344](https://code.castopod.org/adaures/castopod/commit/ce5934419a516c9926dd3fd0ace3c11a95b60722)) +- add podcast banner field for each podcast + refactor images configuration + ([4a8147b](https://code.castopod.org/adaures/castopod/commit/4a8147bfbbd98d9badfc57a0f2a18bdd5812e802)) +- add remote_url alternative for transcript and chapters files + ([3143c9a](https://code.castopod.org/adaures/castopod/commit/3143c9ad36e4cf1364205cf2be39c0c96f80fdd2)) +- add replied to post or comment to reply element + ([d0f9c60](https://code.castopod.org/adaures/castopod/commit/d0f9c6018f1af527099f3e26b5d824710fa11caf)) +- add schema.org json-ld objects to podcasts, episodes, posts and comments pages + ([902f959](https://code.castopod.org/adaures/castopod/commit/902f959b30a10839684f093eb86edebc5d826a0b)) +- add task to housekeeping setting for resetting all instance counts + ([9303e51](https://code.castopod.org/adaures/castopod/commit/9303e51bc50d730a8026f58984e83b840360ee88)) +- add unique listeners analytics + ([3a49258](https://code.castopod.org/adaures/castopod/commit/3a4925816f3268230640525ad7af507aab8eecb9)) +- add user permissions and basic groups to handle authorizations + ([d58e518](https://code.castopod.org/adaures/castopod/commit/d58e51874a4722921b75b0049117015c2380406e)), + closes [#3](https://code.castopod.org/adaures/castopod/issues/3) + [#18](https://code.castopod.org/adaures/castopod/issues/18) +- **admin:** make header stick on scroll and show title + action buttons using + css only + ([d60498c](https://code.castopod.org/adaures/castopod/commit/d60498c1beb970a14eeb3bbe02d1b1d8116624b0)) +- **admin:** update admin layout for better ux + update brand pine colors + ([d86142e](https://code.castopod.org/adaures/castopod/commit/d86142ebe7cd7582835f180b79fbeaaaba703528)) +- allow cross origin requests on episode comments + ([e12f95a](https://code.castopod.org/adaures/castopod/commit/e12f95aca13c6d54489a9cfd99d4cd2490fe83ab)) +- **analytics:** add 'other' group to pie charts in order to display more + accurate data + ([73acef9](https://code.castopod.org/adaures/castopod/commit/73acef933ff3485987afc5157de022910876fc12)) +- **analytics:** add charts and data export + ([78625c4](https://code.castopod.org/adaures/castopod/commit/78625c471b4f03a09bd42f72b82217e1f2d01cef)) +- **analytics:** add service name from rss user-agent + ([7202b98](https://code.castopod.org/adaures/castopod/commit/7202b9867bd59aafa8c338a4230fb5e5c55b24c6)) +- **analytics:** add weekday and hour bar charts + ([8ab3132](https://code.castopod.org/adaures/castopod/commit/8ab313296bb4a254ab05e90b17d896039839b784)) +- build hashed static files to renew browser cache + ([37c54d2](https://code.castopod.org/adaures/castopod/commit/37c54d247749bdf8f528babd4a78f24d48051063)), + closes [#107](https://code.castopod.org/adaures/castopod/issues/107) +- **cache:** add podcast and episode pages to cache + clear them after insert or + update + ([da0f047](https://code.castopod.org/adaures/castopod/commit/da0f0472819007e02e5da37399f2377772c618b9)) +- **categories:** create model, entity, migrations and seeds + ([f73b042](https://code.castopod.org/adaures/castopod/commit/f73b042cc091be82abdbbca8992080875d526972)) +- **clips:** setup clip entities and model + save video clip to have it + generated in the background + ([2f6fdf9](https://code.castopod.org/adaures/castopod/commit/2f6fdf9091d52ca49709fc82621ba1c6dd0e817d)) +- **comments:** add comments to episodes + update naming of status to post + ([bb4752c](https://code.castopod.org/adaures/castopod/commit/bb4752c35e086664f5fd75fdc0d56546a1e356f6)) +- **comments:** add like / undo like to comment + add comment page + ([0c187ef](https://code.castopod.org/adaures/castopod/commit/0c187ef7a9278a60bcc6e5ee4d69d948b51e5c54)) +- **components:** add custom view renderer with ComponentRenderer adapted from + bonfire2 + ([a95de8b](https://code.castopod.org/adaures/castopod/commit/a95de8bab010f6b01c598da72191abe97e473687)) +- create optimized & resized images upon upload + ([02e4441](https://code.castopod.org/adaures/castopod/commit/02e4441f98f27e9534e5b9b63279153d14632ccd)), + closes [#6](https://code.castopod.org/adaures/castopod/issues/6) +- **custom-rss:** add custom xml tag injection in rss feed for ❬channel❭ and + ❬item❭ + ([6ecdaad](https://code.castopod.org/adaures/castopod/commit/6ecdaad911d06b7f7a2b7d24710968c7eb9118f6)) +- **devcontainer:** add devcontainer settings for dev environment + ([69e7266](https://code.castopod.org/adaures/castopod/commit/69e72667365247b63430dee88194e8f0d7c28edc)) +- display castopod version in admin footer + ([9f2574e](https://code.castopod.org/adaures/castopod/commit/9f2574e6fbb61dac4e1a4252dff30017685da5f0)), + closes [#68](https://code.castopod.org/adaures/castopod/issues/68) +- display legal disclaimer and warning on podcast import page + ([2f07992](https://code.castopod.org/adaures/castopod/commit/2f07992e5508b34b91f194eebfac80c51e80e90a)), + closes [#34](https://code.castopod.org/adaures/castopod/issues/34) +- edit + delete podcast and episode + ([ac5f0c7](https://code.castopod.org/adaures/castopod/commit/ac5f0c732806e955c01e05b7867801bc938c6bd5)) +- **embeddable-player:** add embeddable player widget + ([141788f](https://code.castopod.org/adaures/castopod/commit/141788fa089f9dedc8956c64ca515a4a4625f904)) +- enhance admin ui with responsive design and ux improvements + ([2d44b45](https://code.castopod.org/adaures/castopod/commit/2d44b457a02205d2e7da258d7029b8bc5da39533)), + closes [#31](https://code.castopod.org/adaures/castopod/issues/31) + [#9](https://code.castopod.org/adaures/castopod/issues/9) +- enhance ui using javascript in admin area + ([c0e66d5](https://code.castopod.org/adaures/castopod/commit/c0e66d5f7012026e145d106f4d6bd3ba792a1b77)) +- **episodes:** add create form and view pages for episode + ([f3b2c8b](https://code.castopod.org/adaures/castopod/commit/f3b2c8b84f3d93bef734e34dbe8ed729535e45e9)), + closes [#1](https://code.castopod.org/adaures/castopod/issues/1) +- **episodes:** add migrations, model and entity for episodes table + ([0444821](https://code.castopod.org/adaures/castopod/commit/044482174ede555ce19a2d8c6f48771cc8e7d27b)) +- **episodes:** replace all audio file URL parameters with base64 encoded data + ([e1f65cd](https://code.castopod.org/adaures/castopod/commit/e1f65cd3b53353a30d4ab6eb5312393cf04a1676)) +- **episodes:** schedule episode with future publication_date by using cache + expiration time + ([4f1e773](https://code.castopod.org/adaures/castopod/commit/4f1e773c0f9e4c2597f6c1b0a4773dfb34b2f203)), + closes [#47](https://code.castopod.org/adaures/castopod/issues/47) +- **fediverse:** implement activitypub protocols + update user interface + ([2f525c0](https://code.castopod.org/adaures/castopod/commit/2f525c0f6e44d320bff16e22c223481923ba683e)), + closes [#69](https://code.castopod.org/adaures/castopod/issues/69) + [#65](https://code.castopod.org/adaures/castopod/issues/65) + [#85](https://code.castopod.org/adaures/castopod/issues/85) + [#51](https://code.castopod.org/adaures/castopod/issues/51) + [#91](https://code.castopod.org/adaures/castopod/issues/91) + [#92](https://code.castopod.org/adaures/castopod/issues/92) + [#88](https://code.castopod.org/adaures/castopod/issues/88) +- **fonts:** replace Montserrat with Inter for better readablity + ([bfa11d0](https://code.castopod.org/adaures/castopod/commit/bfa11d007d04b8ac714c8cf3b8050a6aaf177a26)) +- import podcast from an rss feed url + ([9a5d5a1](https://code.castopod.org/adaures/castopod/commit/9a5d5a15b4945eb319da9e999c4ca60a0a4f6d2d)), + closes [#21](https://code.castopod.org/adaures/castopod/issues/21) +- integrate stylized form components and update podcast edit page + ([6536729](https://code.castopod.org/adaures/castopod/commit/653672954606a23796e8a7bda3c34fd6b92f84e0)) +- make displayed publication time as relative time using @github/time-elements + ([230e139](https://code.castopod.org/adaures/castopod/commit/230e139e43324b9ebef06ca8f6e13b3d9a7bdc70)) +- **map:** display geolocated episodes on a map page + ([4357cc2](https://code.castopod.org/adaures/castopod/commit/4357cc25ccc585ce398035c1c25d566b6a9df775)) +- **media:** clean media api + create an entity per media type + ([fafaa7e](https://code.castopod.org/adaures/castopod/commit/fafaa7e689b17f09a2b056081fa1f4fc53bf716b)) +- **media:** save audio, images, transcripts and chapters to media for episode + and persons + ([58e2a00](https://code.castopod.org/adaures/castopod/commit/58e2a00a87fa7d5b188e13cc521d94f0cfddba50)) +- **meta-tags:** add activitypub alternate links to podcast, episode, comment + and post pages + ([bd61752](https://code.castopod.org/adaures/castopod/commit/bd61752be2f574323b05d1d0aee0df55adf9a74e)) +- minor corrections to some tables + ([3bf9420](https://code.castopod.org/adaures/castopod/commit/3bf9420b5956a501b3b24405d243a71a928d6086)) +- **monetization:** add Web Monetization support + ([96a6026](https://code.castopod.org/adaures/castopod/commit/96a6026f1db452085360f5fe248de82a2ec06468)) +- **nodeinfo2:** add .well-known route for nodeinfo2 containing metadata about + the castopod instance + ([88fddc8](https://code.castopod.org/adaures/castopod/commit/88fddc81d730978f2a4d8a671936b54041e3fe45)) +- **partner:** add link and image in episode description + ([ad07bb9](https://code.castopod.org/adaures/castopod/commit/ad07bb9330dc9493813368e969e1f3a3def44614)) +- **person:** add podcastindex.org namespace person tag + ([8acd011](https://code.castopod.org/adaures/castopod/commit/8acd011f13e99492ef4b44b327685bb006fe5f8f)) +- **platforms:** add AntennaPod + ([53e9cfd](https://code.castopod.org/adaures/castopod/commit/53e9cfd61c794b1539e9d4691d3c4e73c4b7aaa7)) +- **platforms:** add Fediverse and some funding platforms, add link on logo + ([afc3d50](https://code.castopod.org/adaures/castopod/commit/afc3d50289bb4173e0697d109ffe72f6814b93d1)) +- **platforms:** add helloasso + ([16cb993](https://code.castopod.org/adaures/castopod/commit/16cb993ee6e28987a840fc27a9c2c73794c67697)) +- **platforms:** add missing newpodcastapps.com's platforms + ([92dd370](https://code.castopod.org/adaures/castopod/commit/92dd370e2f9a464edd26cddcde96d0e16f91548d)) +- **platforms:** add pod.link + ([3d7a232](https://code.castopod.org/adaures/castopod/commit/3d7a2320ddd116e4a311605421126aff57243219)) +- **platforms:** add Podcast Index + ([ad52b1c](https://code.castopod.org/adaures/castopod/commit/ad52b1cc2b7d0bc844970214d205961a7196b4a9)) +- **platforms:** add podfriend + ([9fdc8d3](https://code.castopod.org/adaures/castopod/commit/9fdc8d32930234c7ffd2be6892be57febcef1086)) +- **podcast-form:** update routes and redirect to podcast page + ([12ce905](https://code.castopod.org/adaures/castopod/commit/12ce905799002dc9c07e6de092342d30ba9fd7d8)) +- **podcast:** create a podcast using form + ([1202ba3](https://code.castopod.org/adaures/castopod/commit/1202ba3545f521097c60a6a2af95e70527cd1d34)) +- prefill season and episode numbers + set episode number as mandatory for + serial podcasts + ([07d740b](https://code.castopod.org/adaures/castopod/commit/07d740b79f9283e389e723954f680f909ce5de4a)), + closes [#134](https://code.castopod.org/adaures/castopod/issues/134) + [#136](https://code.castopod.org/adaures/castopod/issues/136) +- **public-ui:** adapt public podcast and episode pages to wireframes + ([40a0535](https://code.castopod.org/adaures/castopod/commit/40a0535fc1bc12a24994b651f5e00b35995cbdda)), + closes [#30](https://code.castopod.org/adaures/castopod/issues/30) + [#13](https://code.castopod.org/adaures/castopod/issues/13) +- **pwa:** add service-worker + webmanifest for each podcasts to have them + install on devices + ([fee2c1c](https://code.castopod.org/adaures/castopod/commit/fee2c1c0d0d03c4ff0a6a207b0a5e0c22bb7b13a)) +- redesign public podcast and episode pages + remove any information clutter for + better ux + ([9321400](https://code.castopod.org/adaures/castopod/commit/932140077c671f0486a2cd08ceb6126c7ecde87f)) +- replace form helper functions with components in admin template + ([e64548b](https://code.castopod.org/adaures/castopod/commit/e64548b982ba47ff35f2272e2e30dd85eeba950b)) +- replace slug field with interactive permalink component + ([578022b](https://code.castopod.org/adaures/castopod/commit/578022b8c5163ffaf8db5870ed5ec9d5d9536477)) +- restyle episode and person cards + add focus style to interactive elements for + a11y + ([a505a1d](https://code.castopod.org/adaures/castopod/commit/a505a1de56e8e3056379bd60d0595f432e294728)) +- **rss:** add ˂podcast:guid˃ tag for channel + ([1fab10e](https://code.castopod.org/adaures/castopod/commit/1fab10eb0d63bb7c3edf34ffe691e2aec2c2e43c)) +- **rss:** add podcast-namespace tags for platforms + previousUrl tag + ([dbba8dc](https://code.castopod.org/adaures/castopod/commit/dbba8dc58133967c778514268cbfed8098ed1dbc)), + closes [#73](https://code.castopod.org/adaures/castopod/issues/73) + [#75](https://code.castopod.org/adaures/castopod/issues/75) + [#76](https://code.castopod.org/adaures/castopod/issues/76) + [#80](https://code.castopod.org/adaures/castopod/issues/80) +- **rss:** add podcast:comments tag to link to episode comments + ([32e8c7c](https://code.castopod.org/adaures/castopod/commit/32e8c7c16a61ffe08e2f3bfbdeda556811a0358c)) +- **rss:** add podcast:location tag + ([c0a2282](https://code.castopod.org/adaures/castopod/commit/c0a22829bd87d48535a86e60c6cd7280e44683a2)) +- **rss:** add soundbites according to the podcastindex specs + ([6b34617](https://code.castopod.org/adaures/castopod/commit/6b34617d07c70522cb941e96d91d9987493413eb)), + closes [#83](https://code.castopod.org/adaures/castopod/issues/83) +- **rss:** add transcript and chapters support + ([e769d83](https://code.castopod.org/adaures/castopod/commit/e769d83a932c169e52a630a17cd4dd8ac5cebaf6)), + closes [#72](https://code.castopod.org/adaures/castopod/issues/72) + [#82](https://code.castopod.org/adaures/castopod/issues/82) +- **rss:** generate rss feed from podcast entity + ([c815ecd](https://code.castopod.org/adaures/castopod/commit/c815ecd6640931fee0895f80908a3ddfac482666)) +- **rss:** update monetization tag so that it meets PodcastIndex requirements + ([4c7ecbe](https://code.castopod.org/adaures/castopod/commit/4c7ecbee83950e5f9f2482cedaab18a1ac9bfc9e)) +- **select:** enhance select input with choices.js + ([910d457](https://code.castopod.org/adaures/castopod/commit/910d457cf843e0fc334b3505a4727d51633395ac)) +- set app parameter forceGlobalSecureRequests = true forcing requests to go + through https + ([d9dff1b](https://code.castopod.org/adaures/castopod/commit/d9dff1b8bf89c8b526ad6cb89f98a1f160d49117)) +- set podcast / episode description in the pages description meta tag + ([1c4a504](https://code.castopod.org/adaures/castopod/commit/1c4a50442bea2d3449efce9c5ff1c80743152f55)), + closes [#44](https://code.castopod.org/adaures/castopod/issues/44) +- **settings:** add general config for instance (site name, description and + icon) + ([5c56f3e](https://code.castopod.org/adaures/castopod/commit/5c56f3e6f00a61af2ccf50811c155c325f2b10fa)) +- **settings:** add theme settings to set an accent color for all public pages + ([5c529a8](https://code.castopod.org/adaures/castopod/commit/5c529a83aa6d6147d94e5aee996e6b0ab02f0ce4)) +- simplify podcast page's layout for better ux + ([2c0efc6](https://code.castopod.org/adaures/castopod/commit/2c0efc6563604dd067be88cfc9ddd88a01745e64)) +- **soundbites:** add soundbite list and creation forms with audio-clipper + component + ([de19317](https://code.castopod.org/adaures/castopod/commit/de19317138a2106deb825c1eed7dda036ed7dac3)) +- style file inputs using tailwind's file class + ([8208ab6](https://code.castopod.org/adaures/castopod/commit/8208ab6785aae8c49f78eb9ac8cd53d77ec8e5e5)) +- **themes:** add ViewThemes library to set views in root themes folder + ([7a27676](https://code.castopod.org/adaures/castopod/commit/7a276764e6a1ee3619d9d3488f6163215db75338)) +- **themes:** set different default banner per theme + ([11c916f](https://code.castopod.org/adaures/castopod/commit/11c916fe433eb749ac32230c48e256057564cbb0)) +- **themes:** set generic css variables for colors to enable instance themes + ([a746a78](https://code.castopod.org/adaures/castopod/commit/a746a781b4bfc78209cf8302c6d7bb3cb452e446)) +- toggle podcast sidebar on smaller screens + ([f0205ec](https://code.castopod.org/adaures/castopod/commit/f0205ec274414e881cba40d6776126f05eaee583)) +- **transcript:** parse srt subtitles into json file + add max file size info + below audio file input + ([0098761](https://code.castopod.org/adaures/castopod/commit/00987610a068c8d6cdd4421ea16585fa037eb61a)) +- **ui:** create ViewComponents library to enable building class and view files + components + ([94872f2](https://code.castopod.org/adaures/castopod/commit/94872f2338e6025c2f3770be256160838dae9003)) +- update analytics so to meet IABv2 requirements + ([03e23a2](https://code.castopod.org/adaures/castopod/commit/03e23a28bf9b1b73fba55352c36a8cd6cc8ae729)), + closes [#10](https://code.castopod.org/adaures/castopod/issues/10) +- update pine colors + create charts components + ([a50abc1](https://code.castopod.org/adaures/castopod/commit/a50abc138d4997b564e3065b37504cda5ce62da6)) +- **users:** add myth-auth to handle users crud + add admin gateway only + accessible by login + ([c63a077](https://code.castopod.org/adaures/castopod/commit/c63a077618c61b4cde7f25ffc650a4b0e1495f44)), + closes [#11](https://code.castopod.org/adaures/castopod/issues/11) +- **ux:** remove admin dashboard and redirect directly to podcast list + ([27c48b8](https://code.castopod.org/adaures/castopod/commit/27c48b8fa930b33e5e15f0c8685e468e857ca9cd)) +- **video-clip:** add video-clip page with video preview + logs + ([42538dd](https://code.castopod.org/adaures/castopod/commit/42538dd7577be0ffe59b4fdfadbd76cc89e5ef30)) +- **video-clip:** generate video clips in the bg using a cron job + add video + clip page + tidy up UI + ([db0e427](https://code.castopod.org/adaures/castopod/commit/db0e4272bd6d307c562e1f961d2747cb62de0f35)) +- **video-clips:** add dimensions for portrait and squared formats + ([3af404d](https://code.castopod.org/adaures/castopod/commit/3af404da3dd1901c78cc7e1778fc225f6716207d)) +- **video-clips:** add new themes + add castopod logo as a watermark + ([1d1490b](https://code.castopod.org/adaures/castopod/commit/1d1490b06a1f5ecb10b3b98a72efc55d09c10944)) +- **video-clips:** add route for scheduled video clips + list video clips with + status + ([2065ebb](https://code.castopod.org/adaures/castopod/commit/2065ebbee5e3d0f890ac90b55ca984f1d62a184c)) +- **video-clips:** allow episodeNumbering text to stand in the indent of + episodeTitle paragraph + ([71a063d](https://code.castopod.org/adaures/castopod/commit/71a063dac311cb21639801fbae6af7c5106c2699)) +- **video-clips:** generate a 16:9 video using ffmpeg + ([35aa7ea](https://code.castopod.org/adaures/castopod/commit/35aa7ea5d9a339b3e6f745137282268d69fe2231)) +- **video-clips:** generate subtitles clip using transcript json to have + subtitles accross video + ([3ce07e4](https://code.castopod.org/adaures/castopod/commit/3ce07e455d171e29be30d8ad45055510eb8d363c)) +- **video-clips:** replace hardcoded colors with config's theme colors + ([e462abf](https://code.castopod.org/adaures/castopod/commit/e462abf6d660e41d2170c52caf45704008de58e9)) +- **vite:** add vite config to decouple it from CI_ENVIRONMENT + ([8721719](https://code.castopod.org/adaures/castopod/commit/8721719cd7cf32e94823541eafaba1e9309355a8)) +- write id3v2 tags to episode's audio file + ([4651d01](https://code.castopod.org/adaures/castopod/commit/4651d01a84ff3ea8433a8ae26cfd750a1ec9e88d)) + +### Performance Improvements + +- **cache:** update CI4 to use cache's deleteMatching method + ([54b84f9](https://code.castopod.org/adaures/castopod/commit/54b84f96843af13f579fea49102c8c2ef81b0a54)) +- **cache:** use deleteMatching method to prevent forgetting cached elements in + models + ([76afc0c](https://code.castopod.org/adaures/castopod/commit/76afc0cfa2feb087697bae4bc138e4956873dd62)) +- defer javascript + lazy load images for faster page loads + ([f0685e4](https://code.castopod.org/adaures/castopod/commit/f0685e44799dfb494592ff97841c0ae035381db8)) +- **docker:** add redis caching service for development + ([05ace8c](https://code.castopod.org/adaures/castopod/commit/05ace8cff2ef02d19abd40097ac5546dca6a54ca)) + +### Reverts + +- set deprecated config options back in App config + ([433745f](https://code.castopod.org/adaures/castopod/commit/433745f194c73407999b207090478563283876a5)) +- **soundbites:** remove soundbite table from episode's public page + ([5dc0f19](https://code.castopod.org/adaures/castopod/commit/5dc0f19656de0d764f627d6ae78a9e306c901835)) +- use basic input file for episodes audio files instead of button for better UX + ([d5f22fb](https://code.castopod.org/adaures/castopod/commit/d5f22fbb38c43d9b37df401eff655958a57cb40a)) + +### BREAKING CHANGES + +- **analytics:** analytics_podcasts_by_player table and analytics_podcasts + procedure were updated + +# [1.0.0-alpha.80](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.79...v1.0.0-alpha.80) (2021-12-29) + +### Bug Fixes + +- add application/octet-stream mimetype to mp3 and m4a extensions to prevent + ext_in error + ([339bef8](https://code.castopod.org/adaures/castopod/commit/339bef878e54983d86e91e6ff7a931a843d321b3)), + closes [#145](https://code.castopod.org/adaures/castopod/issues/145) + +# [1.0.0-alpha.79](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.78...v1.0.0-alpha.79) (2021-12-20) + +### Bug Fixes + +- **import:** set episode and season numbers to null when not present in item + tag + ([3211398](https://code.castopod.org/adaures/castopod/commit/3211398c78b1b28b76a46427ee07874bbf84a85d)) + +# [1.0.0-alpha.78](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.77...v1.0.0-alpha.78) (2021-12-15) + +### Bug Fixes + +- **import:** add extension when downloading file without + truncate slug if too + long + ([c5f18bb](https://code.castopod.org/adaures/castopod/commit/c5f18bb6dc08a758ff735454bbe9cfa45a68c09b)) + +# [1.0.0-alpha.77](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.76...v1.0.0-alpha.77) (2021-11-23) + +### Bug Fixes + +- **cors:** add preflight option routes for episode, podcast and status objects + ([a281abf](https://code.castopod.org/adaures/castopod/commit/a281abfda475388a07943c169dab460cc2d4f944)) +- **podcast-import:** move guid attribute declaration for Episode entity to + include slug data + ([5d02ae3](https://code.castopod.org/adaures/castopod/commit/5d02ae39908a9d743627135b372bf981134c4328)) + +# [1.0.0-alpha.76](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.75...v1.0.0-alpha.76) (2021-10-26) + +### Bug Fixes + +- replace hardcoded style links with vite service + set default value for remote + transcript url + ([3f2e056](https://code.castopod.org/adaures/castopod/commit/3f2e05608e43d47bbb518a9acfaf56ec3eefafb4)), + closes [#149](https://code.castopod.org/adaures/castopod/issues/149) + [#150](https://code.castopod.org/adaures/castopod/issues/150) + +# [1.0.0-alpha.75](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.74...v1.0.0-alpha.75) (2021-10-05) + +### Bug Fixes + +- **rss:** cast number type values to string in rss_helper + ([7180ae9](https://code.castopod.org/adaures/castopod/commit/7180ae9ec700930b69c04ed91f8eceea16ad77ce)), + closes [#148](https://code.castopod.org/adaures/castopod/issues/148) + +# [1.0.0-alpha.74](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.73...v1.0.0-alpha.74) (2021-09-28) + +### Features + +- **platforms:** add missing newpodcastapps.com's platforms + ([92dd370](https://code.castopod.org/adaures/castopod/commit/92dd370e2f9a464edd26cddcde96d0e16f91548d)) + +# [1.0.0-alpha.73](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.72...v1.0.0-alpha.73) (2021-09-22) + +### Bug Fixes + +- **map:** update episode markers query to discard unpublished episodes + ([b3caac4](https://code.castopod.org/adaures/castopod/commit/b3caac45b12a23e4289d00133d2ad7915d084c44)) + +# [1.0.0-alpha.72](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.71...v1.0.0-alpha.72) (2021-09-20) + +### Bug Fixes + +- rename field status to task_status to get scheduled activities + ([4ff82a5](https://code.castopod.org/adaures/castopod/commit/4ff82a5f0a38dbbc9e272fca7df70ea5a190e334)) + +# [1.0.0-alpha.71](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.70...v1.0.0-alpha.71) (2021-09-17) + +### Features + +- **map:** display geolocated episodes on a map page + ([4357cc2](https://code.castopod.org/adaures/castopod/commit/4357cc25ccc585ce398035c1c25d566b6a9df775)) + +# [1.0.0-alpha.70](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.69...v1.0.0-alpha.70) (2021-08-31) + +### Bug Fixes + +- **partner:** set correct image URL + ([61554be](https://code.castopod.org/adaures/castopod/commit/61554be12a64d59ab99fab810b1b05632b408f3a)) + +# [1.0.0-alpha.69](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.68...v1.0.0-alpha.69) (2021-08-23) + +### Bug Fixes + +- **import:** cast description's SimpleXMLElement to string + ([02d17be](https://code.castopod.org/adaures/castopod/commit/02d17be4ffe229fc6657207d31eba0543b5f1a4c)) + +# [1.0.0-alpha.68](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.67...v1.0.0-alpha.68) (2021-08-19) + +### Bug Fixes + +- **analytics:** redirect to mp3 file even when referer was not set + ([9fc388d](https://code.castopod.org/adaures/castopod/commit/9fc388d154f29c335dedcd624abe8c1751762c07)) + +# [1.0.0-alpha.67](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.66...v1.0.0-alpha.67) (2021-07-24) + +### Features + +- allow cross origin requests on episode comments + ([e12f95a](https://code.castopod.org/adaures/castopod/commit/e12f95aca13c6d54489a9cfd99d4cd2490fe83ab)) + +# [1.0.0-alpha.66](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.65...v1.0.0-alpha.66) (2021-07-24) + +### Features + +- **rss:** add podcast:comments tag to link to episode comments + ([32e8c7c](https://code.castopod.org/adaures/castopod/commit/32e8c7c16a61ffe08e2f3bfbdeda556811a0358c)) + +# [1.0.0-alpha.65](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.64...v1.0.0-alpha.65) (2021-07-22) + +### Bug Fixes + +- update conditions when checking for empty max_episodes and season_number + ([fbad0b5](https://code.castopod.org/adaures/castopod/commit/fbad0b59f68c65eba2fdcd5a8d3b312b622e9a45)) + +# [1.0.0-alpha.64](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.63...v1.0.0-alpha.64) (2021-07-12) + +### Features + +- **activitypub:** add Podcast actor and PodcastEpisode object with comments + ([9e1e5d2](https://code.castopod.org/adaures/castopod/commit/9e1e5d2e862d6a3345d11ca7f96b955c76bfa013)) + +# [1.0.0-alpha.63](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.62...v1.0.0-alpha.63) (2021-07-12) + +### Features + +- build hashed static files to renew browser cache + ([37c54d2](https://code.castopod.org/adaures/castopod/commit/37c54d247749bdf8f528babd4a78f24d48051063)), + closes [#107](https://code.castopod.org/adaures/castopod/issues/107) + +# [1.0.0-alpha.62](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.61...v1.0.0-alpha.62) (2021-07-02) + +### Bug Fixes + +- **episode:** replace guid's empty string value to null + ([441052a](https://code.castopod.org/adaures/castopod/commit/441052af8d99e6e317edefd1e58ad71799357088)) + +# [1.0.0-alpha.61](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.60...v1.0.0-alpha.61) (2021-06-23) + +### Bug Fixes + +- **release:** add missing version number to castopod-host package + ([8f3e9d9](https://code.castopod.org/adaures/castopod/commit/8f3e9d90c14545d3f84d4469b26a53db4554b4dc)) +- **ux:** allow for empty message upon episode publication and warn user on + submit + ([33d01b8](https://code.castopod.org/adaures/castopod/commit/33d01b8d4fd6ebf24e9f011aa705c456c846956c)), + closes [#129](https://code.castopod.org/adaures/castopod/issues/129) + +# [1.0.0-alpha.60](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.59...v1.0.0-alpha.60) (2021-06-21) + +### Features + +- **rss:** add ˂podcast:guid˃ tag for channel + ([1fab10e](https://code.castopod.org/adaures/castopod/commit/1fab10eb0d63bb7c3edf34ffe691e2aec2c2e43c)) + +# [1.0.0-alpha.59](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.58...v1.0.0-alpha.59) (2021-06-15) + +### Bug Fixes + +- check that additional files are valid when creating episode + ([eac5bc8](https://code.castopod.org/adaures/castopod/commit/eac5bc876de125e1fe08d1b89f767a04fc0fbfb6)) + +# [1.0.0-alpha.58](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.57...v1.0.0-alpha.58) (2021-06-11) + +### Bug Fixes + +- cast actor_id to pass as int to set_interact_as_actor() function + ([56a8e5d](https://code.castopod.org/adaures/castopod/commit/56a8e5d7dd615322aeb007e730801c65d0b02e5c)) +- **analytics:** set duration field to precise decimal as episode's audio file + duration + ([d772685](https://code.castopod.org/adaures/castopod/commit/d77268540569b2be9d91d5e09aefb3ff5ac2b071)) +- **analytics:** update migrations to set decimal precision for latitude and + longitude + ([714d6b5](https://code.castopod.org/adaures/castopod/commit/714d6b5d4950e52cf1c3170bb59954f98ffd48bd)) +- check for database connection and podcasts table existence before redirecting + to install + ([eb74e81](https://code.castopod.org/adaures/castopod/commit/eb74e81c3d93581e310b391cd029e62a0d690a8a)) +- save transcript and chapters files to podcasts folder + ([63f49c7](https://code.castopod.org/adaures/castopod/commit/63f49c719f672b615c5a8893d3868dffcd332e47)) +- set cache expiration to next note publish to show note on publication date + ([0a66de3](https://code.castopod.org/adaures/castopod/commit/0a66de3e6c17d4ac94ee8e13bd00ceaf64b1303e)) +- set episode description footer to null when empty value + ([3a7d97d](https://code.castopod.org/adaures/castopod/commit/3a7d97d660046d80698611311ff3708110d2af82)) +- set location to null when getting empty string + ([71b1b5f](https://code.castopod.org/adaures/castopod/commit/71b1b5f775af475b1dc78328330e277f565e41b6)) +- update condition in home controller to redirect to install page + ([33f1b91](https://code.castopod.org/adaures/castopod/commit/33f1b91d55dd0652c979d50fc85879dbf88a4a42)) +- **activity-pub:** cache issues when navigating to activity stream urls + ([7bcbfb3](https://code.castopod.org/adaures/castopod/commit/7bcbfb32f7cca08d111be46c7f1640e372d4a4b0)) +- **activity-pub:** get database records using new model instances + ([92536dd](https://code.castopod.org/adaures/castopod/commit/92536ddb3812214a9c5682b92e547e5c1998a5d7)) +- **category:** remove uncategorized option to enforce users in choosing a + category + ([8c64f25](https://code.castopod.org/adaures/castopod/commit/8c64f25a0e72fec03d25544797d32623b2276fce)) +- **install:** redirect manually to install wizard on first visit + ([2ceaaca](https://code.castopod.org/adaures/castopod/commit/2ceaaca44f1b82fc64d961e2fb4f4aaeade7e736)) +- **types:** update fake seeders types + fix bugs + ([76a4bf3](https://code.castopod.org/adaures/castopod/commit/76a4bf344160df679db29e236e7df7822970fb60)) +- update broken contributor dropdown fields + ([e5b7515](https://code.castopod.org/adaures/castopod/commit/e5b75150234bd7f19e01def93425d3bda7379dd3)) +- **ux:** redirect user to install page on database error in home page + ([9017e30](https://code.castopod.org/adaures/castopod/commit/9017e30bf41bed8c2be65091bbc5fb1e63aef87a)) +- update condition in AnalyticsTrait + ([fbc0967](https://code.castopod.org/adaures/castopod/commit/fbc0967caa81630d514ddb1b93b0834ebb4d913b)) + +### Performance Improvements + +- **cache:** use deleteMatching method to prevent forgetting cached elements in + models + ([76afc0c](https://code.castopod.org/adaures/castopod/commit/76afc0cfa2feb087697bae4bc138e4956873dd62)) + +### Reverts + +- set deprecated config options back in App config + ([433745f](https://code.castopod.org/adaures/castopod/commit/433745f194c73407999b207090478563283876a5)) + +# [1.0.0-alpha.57](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.56...v1.0.0-alpha.57) (2021-05-12) + +### Bug Fixes + +- **follow:** add missing helpers to Actor controller + ([ee53a73](https://code.castopod.org/adaures/castopod/commit/ee53a732dc12ebbf5706e14969749a12cfd9d559)) + +# [1.0.0-alpha.56](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.55...v1.0.0-alpha.56) (2021-05-12) + +### Bug Fixes + +- **rss:** use originalPath instead of originalMediaPath in Image library + ([b4012b7](https://code.castopod.org/adaures/castopod/commit/b4012b7d2ed6b34b69ad767570dd33f0dc7db920)) + +# [1.0.0-alpha.55](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.54...v1.0.0-alpha.55) (2021-05-03) + +### Features + +- add remote_url alternative for transcript and chapters files + ([3143c9a](https://code.castopod.org/adaures/castopod/commit/3143c9ad36e4cf1364205cf2be39c0c96f80fdd2)) + +# [1.0.0-alpha.54](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.53...v1.0.0-alpha.54) (2021-05-03) + +### Features + +- set app parameter forceGlobalSecureRequests = true forcing requests to go + through https + ([d9dff1b](https://code.castopod.org/adaures/castopod/commit/d9dff1b8bf89c8b526ad6cb89f98a1f160d49117)) +- **ux:** remove admin dashboard and redirect directly to podcast list + ([27c48b8](https://code.castopod.org/adaures/castopod/commit/27c48b8fa930b33e5e15f0c8685e468e857ca9cd)) +- add cache to ActivityPub sql queries + cache activity and note pages + ([2d297f4](https://code.castopod.org/adaures/castopod/commit/2d297f45b3d7ef6e8711875a0b9b908e878115fa)) + +### Performance Improvements + +- **cache:** update CI4 to use cache's deleteMatching method + ([54b84f9](https://code.castopod.org/adaures/castopod/commit/54b84f96843af13f579fea49102c8c2ef81b0a54)) +- **docker:** add redis caching service for development + ([05ace8c](https://code.castopod.org/adaures/castopod/commit/05ace8cff2ef02d19abd40097ac5546dca6a54ca)) + +# [1.0.0-alpha.53](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.52...v1.0.0-alpha.53) (2021-04-16) + +### Bug Fixes + +- check that note has a preview_card_id before displaying it + ([acb8b3a](https://code.castopod.org/adaures/castopod/commit/acb8b3a40172ccb184ffe544760601d756692e6c)), + closes [#114](https://code.castopod.org/adaures/castopod/issues/114) + +# [1.0.0-alpha.52](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.51...v1.0.0-alpha.52) (2021-04-16) + +### Bug Fixes + +- **avatar:** use default avatar when no avatar url has been set + ([9d23c7e](https://code.castopod.org/adaures/castopod/commit/9d23c7e7e142c6cf1a1418e37e41d711064593c4)), + closes [#111](https://code.castopod.org/adaures/castopod/issues/111) + +# [1.0.0-alpha.51](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.50...v1.0.0-alpha.51) (2021-04-15) + +### Bug Fixes + +- **interact-as:** set actor_id instead of podcast id upon login event + ([5dfade7](https://code.castopod.org/adaures/castopod/commit/5dfade7cf37f339c56d2e577c679b88a1b1d9336)), + closes [#104](https://code.castopod.org/adaures/castopod/issues/104) + +# [1.0.0-alpha.50](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.49...v1.0.0-alpha.50) (2021-04-14) + +### Bug Fixes + +- **persons:** prevent overflow of persons list by adding horizontal scroll + ([9e8995d](https://code.castopod.org/adaures/castopod/commit/9e8995dc6e039032cc65f87895cf770f99e8b244)) + +# [1.0.0-alpha.49](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.48...v1.0.0-alpha.49) (2021-04-12) + +### Bug Fixes + +- **multiselect:** add missing class names in choices options for purge to work + properly + ([719538d](https://code.castopod.org/adaures/castopod/commit/719538d0ccb28af3c3c5e1a4b6468d4b772fe819)) + +# [1.0.0-alpha.48](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.47...v1.0.0-alpha.48) (2021-04-10) + +### Bug Fixes + +- **import-with-escaped-characters:** remove \CodeIgniter\HTTP\URI in + download_file, closes + [#103](https://code.castopod.org/adaures/castopod/issues/103) + ([35b5be0](https://code.castopod.org/adaures/castopod/commit/35b5be095ff54d27acec1610a846ec0cdbdf1d65)) + +# [1.0.0-alpha.47](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.46...v1.0.0-alpha.47) (2021-04-10) + +### Bug Fixes + +- **episodeCount:** add missing brackets to French language file + ([c1b4112](https://code.castopod.org/adaures/castopod/commit/c1b411265ad9b06e95a8b097ecf73445b88dcb45)) + +# [1.0.0-alpha.46](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.45...v1.0.0-alpha.46) (2021-04-09) + +### Bug Fixes + +- **episodes-page:** handle defaultQuery being null when no podcast episodes + ([15183b7](https://code.castopod.org/adaures/castopod/commit/15183b7eab57dac007bcdfa8c3651239de1ae05a)), + closes [#100](https://code.castopod.org/adaures/castopod/issues/100) + +# [1.0.0-alpha.45](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.44...v1.0.0-alpha.45) (2021-04-08) + +### Bug Fixes + +- add head request to analytics_hit route + ([f0a2f0b](https://code.castopod.org/adaures/castopod/commit/f0a2f0bea491ca91976b351bb79837e95c9d094b)) + +# [1.0.0-alpha.44](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.43...v1.0.0-alpha.44) (2021-04-08) + +### Bug Fixes + +- **rss:** set ❬itunes:author❭ tag to owner_name if publisher not specified + ([2271c14](https://code.castopod.org/adaures/castopod/commit/2271c1445b1ded12bc53b5d23b5e59d12b17c71a)), + closes [#96](https://code.castopod.org/adaures/castopod/issues/96) + +# [1.0.0-alpha.43](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.42...v1.0.0-alpha.43) (2021-04-08) + +### Bug Fixes + +- **episode-form:** show warning to set `memory_limit`, `upload_max_filesize` & + `post_max_size` + ([3b3c218](https://code.castopod.org/adaures/castopod/commit/3b3c218b9c868e9f12c54d7670e69d84c9ee79c0)), + closes [#5](https://code.castopod.org/adaures/castopod/issues/5) + [#86](https://code.castopod.org/adaures/castopod/issues/86) + +# [1.0.0-alpha.42](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.41...v1.0.0-alpha.42) (2021-04-02) + +### Features + +- **fediverse:** implement activitypub protocols + update user interface + ([2f525c0](https://code.castopod.org/adaures/castopod/commit/2f525c0f6e44d320bff16e22c223481923ba683e)), + closes [#69](https://code.castopod.org/adaures/castopod/issues/69) + [#65](https://code.castopod.org/adaures/castopod/issues/65) + [#85](https://code.castopod.org/adaures/castopod/issues/85) + [#51](https://code.castopod.org/adaures/castopod/issues/51) + [#91](https://code.castopod.org/adaures/castopod/issues/91) + [#92](https://code.castopod.org/adaures/castopod/issues/92) + [#88](https://code.castopod.org/adaures/castopod/issues/88) + +# [1.0.0-alpha.41](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.40...v1.0.0-alpha.41) (2021-03-30) + +### Features + +- **partner:** add link and image in episode description + ([ad07bb9](https://code.castopod.org/adaures/castopod/commit/ad07bb9330dc9493813368e969e1f3a3def44614)) + +# [1.0.0-alpha.40](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.39...v1.0.0-alpha.40) (2021-03-19) + +### Features + +- **custom-rss:** add custom xml tag injection in rss feed for ❬channel❭ and + ❬item❭ + ([6ecdaad](https://code.castopod.org/adaures/castopod/commit/6ecdaad911d06b7f7a2b7d24710968c7eb9118f6)) + +# [1.0.0-alpha.39](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.38...v1.0.0-alpha.39) (2021-03-01) + +### Bug Fixes + +- **embeddable-player:** enable any ancestor when X-Frame-Options is set on + server + ([44a4962](https://code.castopod.org/adaures/castopod/commit/44a4962e0b7e3ed87e9914b4e7792a0d52330ff8)) + +# [1.0.0-alpha.38](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.37...v1.0.0-alpha.38) (2021-02-27) + +### Features + +- **embeddable-player:** add embeddable player widget + ([141788f](https://code.castopod.org/adaures/castopod/commit/141788fa089f9dedc8956c64ca515a4a4625f904)) + +# [1.0.0-alpha.37](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.36...v1.0.0-alpha.37) (2021-02-17) + +### Bug Fixes + +- **import:** remove query string from files url + ([109c4aa](https://code.castopod.org/adaures/castopod/commit/109c4aa1afb72dd8b99c0302d74a7fef5a38638e)) + +# [1.0.0-alpha.36](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.35...v1.0.0-alpha.36) (2021-02-16) + +### Features + +- **platforms:** add pod.link + ([3d7a232](https://code.castopod.org/adaures/castopod/commit/3d7a2320ddd116e4a311605421126aff57243219)) + +# [1.0.0-alpha.35](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.34...v1.0.0-alpha.35) (2021-02-12) + +### Bug Fixes + +- **admin:** save block and lock switches + ([b66c0af](https://code.castopod.org/adaures/castopod/commit/b66c0afc8fab2e338402a9a4f8105e5f5459e208)) + +# [1.0.0-alpha.34](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.33...v1.0.0-alpha.34) (2021-02-11) + +### Bug Fixes + +- **rss-import:** add Castopod user-agent, handle redirects for downloaded + files, add Content namespace + ([214243b](https://code.castopod.org/adaures/castopod/commit/214243b3fec4937e45ef1ceaba1149004cdf3b44)) + +# [1.0.0-alpha.33](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.32...v1.0.0-alpha.33) (2021-02-10) + +### Features + +- **platforms:** add helloasso + ([16cb993](https://code.castopod.org/adaures/castopod/commit/16cb993ee6e28987a840fc27a9c2c73794c67697)) + +# [1.0.0-alpha.32](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.31...v1.0.0-alpha.32) (2021-02-10) + +### Features + +- **person:** add podcastindex.org namespace person tag + ([8acd011](https://code.castopod.org/adaures/castopod/commit/8acd011f13e99492ef4b44b327685bb006fe5f8f)) + +# [1.0.0-alpha.31](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.30...v1.0.0-alpha.31) (2020-12-23) + +### Features + +- **rss:** add podcast:location tag + ([c0a2282](https://code.castopod.org/adaures/castopod/commit/c0a22829bd87d48535a86e60c6cd7280e44683a2)) + +# [1.0.0-alpha.30](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.29...v1.0.0-alpha.30) (2020-12-21) + +### Features + +- **rss:** update monetization tag so that it meets PodcastIndex requirements + ([4c7ecbe](https://code.castopod.org/adaures/castopod/commit/4c7ecbee83950e5f9f2482cedaab18a1ac9bfc9e)) + +# [1.0.0-alpha.29](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.28...v1.0.0-alpha.29) (2020-12-10) + +### Bug Fixes + +- **episodes:** add publication status + set publication date to null when none + has been set + ([d882981](https://code.castopod.org/adaures/castopod/commit/d882981b3a86c81921ce6b07d4cf61fc13983689)), + closes [#70](https://code.castopod.org/adaures/castopod/issues/70) + +### Reverts + +- **soundbites:** remove soundbite table from episode's public page + ([5dc0f19](https://code.castopod.org/adaures/castopod/commit/5dc0f19656de0d764f627d6ae78a9e306c901835)) + +# [1.0.0-alpha.28](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.27...v1.0.0-alpha.28) (2020-12-07) + +### Features + +- **rss:** add soundbites according to the podcastindex specs + ([6b34617](https://code.castopod.org/adaures/castopod/commit/6b34617d07c70522cb941e96d91d9987493413eb)), + closes [#83](https://code.castopod.org/adaures/castopod/issues/83) + +# [1.0.0-alpha.27](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.26...v1.0.0-alpha.27) (2020-12-07) + +### Features + +- **platforms:** add AntennaPod + ([53e9cfd](https://code.castopod.org/adaures/castopod/commit/53e9cfd61c794b1539e9d4691d3c4e73c4b7aaa7)) + +# [1.0.0-alpha.26](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.25...v1.0.0-alpha.26) (2020-11-30) + +### Bug Fixes + +- **analytics:** update service management so that it works with new OPAWG slug + values + ([7fe9d42](https://code.castopod.org/adaures/castopod/commit/7fe9d42500ade2c6fa3ff4365b4affc475af0e51)) + +# [1.0.0-alpha.25](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.24...v1.0.0-alpha.25) (2020-11-30) + +### Features + +- **platforms:** add podfriend + ([9fdc8d3](https://code.castopod.org/adaures/castopod/commit/9fdc8d32930234c7ffd2be6892be57febcef1086)) + +# [1.0.0-alpha.24](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.23...v1.0.0-alpha.24) (2020-11-26) + +### Features + +- **monetization:** add Web Monetization support + ([96a6026](https://code.castopod.org/adaures/castopod/commit/96a6026f1db452085360f5fe248de82a2ec06468)) + +# [1.0.0-alpha.23](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.22...v1.0.0-alpha.23) (2020-11-24) + +### Bug Fixes + +- define podcastNamespaceLink value + ([0d744d2](https://code.castopod.org/adaures/castopod/commit/0d744d212df0d070ceea185068eaf2746e1ccd48)) + +# [1.0.0-alpha.22](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.21...v1.0.0-alpha.22) (2020-11-24) + +### Features + +- **rss:** add transcript and chapters support + ([e769d83](https://code.castopod.org/adaures/castopod/commit/e769d83a932c169e52a630a17cd4dd8ac5cebaf6)), + closes [#72](https://code.castopod.org/adaures/castopod/issues/72) + [#82](https://code.castopod.org/adaures/castopod/issues/82) + +# [1.0.0-alpha.21](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.20...v1.0.0-alpha.21) (2020-11-24) + +### Features + +- **platforms:** add Fediverse and some funding platforms, add link on logo + ([afc3d50](https://code.castopod.org/adaures/castopod/commit/afc3d50289bb4173e0697d109ffe72f6814b93d1)) + +# [1.0.0-alpha.20](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.19...v1.0.0-alpha.20) (2020-11-24) + +### Bug Fixes + +- **import:** use tag when no is present + ([20e607a](https://code.castopod.org/adaures/castopod/commit/20e607afb755bc75056041738fa7cbf6723d754c)) + +### Features + +- **rss:** add podcast-namespace tags for platforms + previousUrl tag + ([dbba8dc](https://code.castopod.org/adaures/castopod/commit/dbba8dc58133967c778514268cbfed8098ed1dbc)), + closes [#73](https://code.castopod.org/adaures/castopod/issues/73) + [#75](https://code.castopod.org/adaures/castopod/issues/75) + [#76](https://code.castopod.org/adaures/castopod/issues/76) + [#80](https://code.castopod.org/adaures/castopod/issues/80) + +# [1.0.0-alpha.19](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.18...v1.0.0-alpha.19) (2020-11-13) + +### Bug Fixes + +- handle HEAD requests on podcast_feed route + ([74b2640](https://code.castopod.org/adaures/castopod/commit/74b2640f2a25c4cd6fd8835fc492c2a6893d4950)), + closes [#79](https://code.castopod.org/adaures/castopod/issues/79) + +# [1.0.0-alpha.18](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.17...v1.0.0-alpha.18) (2020-11-09) + +### Features + +- **platforms:** add Podcast Index + ([ad52b1c](https://code.castopod.org/adaures/castopod/commit/ad52b1cc2b7d0bc844970214d205961a7196b4a9)) + +# [1.0.0-alpha.17](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.16...v1.0.0-alpha.17) (2020-11-05) + +### Bug Fixes + +- **open-graph:** replace non existant episode description to podcast + description in podcast page + ([b02584e](https://code.castopod.org/adaures/castopod/commit/b02584ee609af1ad1b5680cc28208d113eb0410b)) + +# [1.0.0-alpha.16](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.15...v1.0.0-alpha.16) (2020-11-04) + +### Features + +- add Open Graph and Twitter meta tags + ([af970b8](https://code.castopod.org/adaures/castopod/commit/af970b8bac949e4c63047e04aca1b7403a4e8deb)), + closes [#41](https://code.castopod.org/adaures/castopod/issues/41) + +# [1.0.0-alpha.15](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.14...v1.0.0-alpha.15) (2020-11-03) + +### Features + +- **analytics:** add 'other' group to pie charts in order to display more + accurate data + ([73acef9](https://code.castopod.org/adaures/castopod/commit/73acef933ff3485987afc5157de022910876fc12)) + +# [1.0.0-alpha.14](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.13...v1.0.0-alpha.14) (2020-11-02) + +### Features + +- **analytics:** add weekday and hour bar charts + ([8ab3132](https://code.castopod.org/adaures/castopod/commit/8ab313296bb4a254ab05e90b17d896039839b784)) + +# [1.0.0-alpha.13](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.12...v1.0.0-alpha.13) (2020-10-29) + +### Bug Fixes + +- **episodes-table:** set descriptions to be not null + ([6774ec1](https://code.castopod.org/adaures/castopod/commit/6774ec10fa78527be6b7548ca1dc34ad0ada090c)) + +### Features + +- add episode_numbering() component helper to display episode and season numbers + ([3f4a6bd](https://code.castopod.org/adaures/castopod/commit/3f4a6bd0b9f870f16107a41b102b6bf734868198)) +- **episodes:** replace all audio file URL parameters with base64 encoded data + ([e1f65cd](https://code.castopod.org/adaures/castopod/commit/e1f65cd3b53353a30d4ab6eb5312393cf04a1676)) + +# [1.0.0-alpha.12](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.11...v1.0.0-alpha.12) (2020-10-26) + +### Bug Fixes + +- replace getWebEnclosureUrl with getEnclosureWebUrl + ([8122cea](https://code.castopod.org/adaures/castopod/commit/8122ceaf8a70050f14b3078f28b024e7d7cdb9ac)) + +# [1.0.0-alpha.11](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.10...v1.0.0-alpha.11) (2020-10-26) + +### Features + +- add CDN url + ([972bcbf](https://code.castopod.org/adaures/castopod/commit/972bcbf65ee119b8641ca3c4e5c0e8cf9ca8dd4f)), + closes [#37](https://code.castopod.org/adaures/castopod/issues/37) + +# [1.0.0-alpha.10](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.9...v1.0.0-alpha.10) (2020-10-26) + +### Bug Fixes + +- **install:** redirect to host_url install route on instanceConfig validation + error + ([99250b1](https://code.castopod.org/adaures/castopod/commit/99250b1868657c249a447399c7ebc69e00d43d1a)) + +# [1.0.0-alpha.9](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.8...v1.0.0-alpha.9) (2020-10-26) + +### Features + +- display castopod version in admin footer + ([9f2574e](https://code.castopod.org/adaures/castopod/commit/9f2574e6fbb61dac4e1a4252dff30017685da5f0)), + closes [#68](https://code.castopod.org/adaures/castopod/issues/68) + +# [1.0.0-alpha.8](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.7...v1.0.0-alpha.8) (2020-10-22) + +### Features + +- **episodes:** schedule episode with future publication_date by using cache + expiration time + ([4f1e773](https://code.castopod.org/adaures/castopod/commit/4f1e773c0f9e4c2597f6c1b0a4773dfb34b2f203)), + closes [#47](https://code.castopod.org/adaures/castopod/issues/47) + +# [1.0.0-alpha.7](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.6...v1.0.0-alpha.7) (2020-10-21) + +### Features + +- **analytics:** add service name from rss user-agent + ([7202b98](https://code.castopod.org/adaures/castopod/commit/7202b9867bd59aafa8c338a4230fb5e5c55b24c6)) + +### BREAKING CHANGES + +- **analytics:** analytics_podcasts_by_player table and analytics_podcasts + procedure were updated + +# [1.0.0-alpha.6](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.5...v1.0.0-alpha.6) (2020-10-20) ### Bug Fixes - **cache:** add locale for podcast and episode pages + clear some persisting cache in models - ([9cec8a8](https://code.podlibre.org/podlibre/castopod/commit/9cec8a81ccbb7239402fe6633dbc31979272302a)), - closes [#42](https://code.podlibre.org/podlibre/castopod/issues/42) - [#61](https://code.podlibre.org/podlibre/castopod/issues/61) + ([9cec8a8](https://code.castopod.org/adaures/castopod/commit/9cec8a81ccbb7239402fe6633dbc31979272302a)), + closes [#42](https://code.castopod.org/adaures/castopod/issues/42) + [#61](https://code.castopod.org/adaures/castopod/issues/61) -# [1.0.0-alpha.5](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.4...v1.0.0-alpha.5) (2020-10-20) +# [1.0.0-alpha.5](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.4...v1.0.0-alpha.5) (2020-10-20) ### Features - add lock podcast according to the Podcastindex podcast-namespace to prevent unauthozized import - ([72b3012](https://code.podlibre.org/podlibre/castopod/commit/72b301272e0b70ded3e2b237391909e3f152ad0b)) + ([72b3012](https://code.castopod.org/adaures/castopod/commit/72b301272e0b70ded3e2b237391909e3f152ad0b)) -# [1.0.0-alpha.4](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.3...v1.0.0-alpha.4) (2020-10-20) +# [1.0.0-alpha.4](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.3...v1.0.0-alpha.4) (2020-10-20) ### Features - **analytics:** add charts and data export - ([78625c4](https://code.podlibre.org/podlibre/castopod/commit/78625c471b4f03a09bd42f72b82217e1f2d01cef)) + ([78625c4](https://code.castopod.org/adaures/castopod/commit/78625c471b4f03a09bd42f72b82217e1f2d01cef)) -# [1.0.0-alpha.3](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.2...v1.0.0-alpha.3) (2020-10-19) +# [1.0.0-alpha.3](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.2...v1.0.0-alpha.3) (2020-10-19) ### Bug Fixes - **analytics:** remove charts empty values + remove useless language cache - ([1678794](https://code.podlibre.org/podlibre/castopod/commit/16787941539ba4014281a366789ea896a9cd2afc)) + ([1678794](https://code.castopod.org/adaures/castopod/commit/16787941539ba4014281a366789ea896a9cd2afc)) -# [1.0.0-alpha.2](https://code.podlibre.org/podlibre/castopod/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2020-10-19) +# [1.0.0-alpha.2](https://code.castopod.org/adaures/castopod/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2020-10-19) ### Features - add cumulative listening time charts - ([588b4d2](https://code.podlibre.org/podlibre/castopod/commit/588b4d28da00bc12d02126e23181690f54d81716)) + ([588b4d2](https://code.castopod.org/adaures/castopod/commit/588b4d28da00bc12d02126e23181690f54d81716)) # 1.0.0-alpha.1 (2020-10-16) ### Bug Fixes - add public/media folder to castopod bundle - ([8053d35](https://code.podlibre.org/podlibre/castopod/commit/8053d3521b481872711dabaaf265d08b9bfbaa87)), - closes [#52](https://code.podlibre.org/podlibre/castopod/issues/52) + ([8053d35](https://code.castopod.org/adaures/castopod/commit/8053d3521b481872711dabaaf265d08b9bfbaa87)), + closes [#52](https://code.castopod.org/adaures/castopod/issues/52) - add where condition to get episode count without deleted episodes - ([7661734](https://code.podlibre.org/podlibre/castopod/commit/7661734ed296654630f3668132671117519145dd)), - closes [#67](https://code.podlibre.org/podlibre/castopod/issues/67) + ([7661734](https://code.castopod.org/adaures/castopod/commit/7661734ed296654630f3668132671117519145dd)), + closes [#67](https://code.castopod.org/adaures/castopod/issues/67) - comment all cache clean after page update to prevent analytics cache deletion - ([e6197a4](https://code.podlibre.org/podlibre/castopod/commit/e6197a4972a3cce3d67dd7972bb54f8720b8e5b7)) + ([e6197a4](https://code.castopod.org/adaures/castopod/commit/e6197a4972a3cce3d67dd7972bb54f8720b8e5b7)) - correct chart data - ([4d3e9c8](https://code.podlibre.org/podlibre/castopod/commit/4d3e9c8c02cdc882e9fe1c29625695b6f83c820a)) + ([4d3e9c8](https://code.castopod.org/adaures/castopod/commit/4d3e9c8c02cdc882e9fe1c29625695b6f83c820a)) - correct percona compatibility issue - ([e53f819](https://code.podlibre.org/podlibre/castopod/commit/e53f819264b2d6902996f11ffcbb7c99295a90ef)) + ([e53f819](https://code.castopod.org/adaures/castopod/commit/e53f819264b2d6902996f11ffcbb7c99295a90ef)) - correct php-fpm issues - ([1ef55d7](https://code.podlibre.org/podlibre/castopod/commit/1ef55d7315bb44abe05f02ec8a84b6b6a557a9a0)) + ([1ef55d7](https://code.castopod.org/adaures/castopod/commit/1ef55d7315bb44abe05f02ec8a84b6b6a557a9a0)) - correct referrer bug - ([ed69b2f](https://code.podlibre.org/podlibre/castopod/commit/ed69b2f5004ed1cd18bac824c08a0df01f5d2637)) + ([ed69b2f](https://code.castopod.org/adaures/castopod/commit/ed69b2f5004ed1cd18bac824c08a0df01f5d2637)) - correction for servers with low int precision - ([31b7828](https://code.podlibre.org/podlibre/castopod/commit/31b7828e77519ef43e9bcfcbdf6c21712f97a571)) + ([31b7828](https://code.castopod.org/adaures/castopod/commit/31b7828e77519ef43e9bcfcbdf6c21712f97a571)) - declare typed properties in PHPDoc for php<7.4 - ([14dd44d](https://code.podlibre.org/podlibre/castopod/commit/14dd44d03d6db0d9ae4198db8e65c92a0e45cb31)), - closes [#23](https://code.podlibre.org/podlibre/castopod/issues/23) + ([14dd44d](https://code.castopod.org/adaures/castopod/commit/14dd44d03d6db0d9ae4198db8e65c92a0e45cb31)), + closes [#23](https://code.castopod.org/adaures/castopod/issues/23) - escape generated feed tag values and remove new lines from public pages meta description - ([6238a43](https://code.podlibre.org/podlibre/castopod/commit/6238a43863210afe8988ad7cf251e6bfc6c8557c)), - closes [#57](https://code.podlibre.org/podlibre/castopod/issues/57) - [#46](https://code.podlibre.org/podlibre/castopod/issues/46) + ([6238a43](https://code.castopod.org/adaures/castopod/commit/6238a43863210afe8988ad7cf251e6bfc6c8557c)), + closes [#57](https://code.castopod.org/adaures/castopod/issues/57) + [#46](https://code.castopod.org/adaures/castopod/issues/46) - fix layout bugs in admin and update translation files - ([a834171](https://code.podlibre.org/podlibre/castopod/commit/a83417180cf61cdfadc5509b0aaa2fdb66592be3)), - closes [#40](https://code.podlibre.org/podlibre/castopod/issues/40) + ([a834171](https://code.castopod.org/adaures/castopod/commit/a83417180cf61cdfadc5509b0aaa2fdb66592be3)), + closes [#40](https://code.castopod.org/adaures/castopod/issues/40) - minor corrections - ([13be386](https://code.podlibre.org/podlibre/castopod/commit/13be386842e94d9def1f7de4720931d8f6935171)) + ([13be386](https://code.castopod.org/adaures/castopod/commit/13be386842e94d9def1f7de4720931d8f6935171)) - move analytics to helper - ([d311917](https://code.podlibre.org/podlibre/castopod/commit/d31191732e41aa106234b5ebe6e54ee02f0ce603)) + ([d311917](https://code.castopod.org/adaures/castopod/commit/d31191732e41aa106234b5ebe6e54ee02f0ce603)) - re-order graph values - ([35f633b](https://code.podlibre.org/podlibre/castopod/commit/35f633b4c71c087d1ddc9bba9e9bbe18de09204f)) + ([35f633b](https://code.castopod.org/adaures/castopod/commit/35f633b4c71c087d1ddc9bba9e9bbe18de09204f)) - remove required for other_categories field and add podcast_id to latest podcasts query - ([5417be0](https://code.podlibre.org/podlibre/castopod/commit/5417be0049288489a19c7b575aa77bd1e2bc0243)) + ([5417be0](https://code.castopod.org/adaures/castopod/commit/5417be0049288489a19c7b575aa77bd1e2bc0243)) - rename issue_templates labels - ([9f00305](https://code.podlibre.org/podlibre/castopod/commit/9f00305844e5a168e89d727fe29892b4ad5e48d6)) + ([9f00305](https://code.castopod.org/adaures/castopod/commit/9f00305844e5a168e89d727fe29892b4ad5e48d6)) - rename MyAccount controller file - ([e109df3](https://code.podlibre.org/podlibre/castopod/commit/e109df3004a3a98d72de39532e062fff9917f50f)), - closes [#60](https://code.podlibre.org/podlibre/castopod/issues/60) + ([e109df3](https://code.castopod.org/adaures/castopod/commit/e109df3004a3a98d72de39532e062fff9917f50f)), + closes [#60](https://code.castopod.org/adaures/castopod/issues/60) - reorder fields as composite primary keys for analytics tables - ([9660aa9](https://code.podlibre.org/podlibre/castopod/commit/9660aa97c8ffd4fe61f3a388d52b9ac5dd8e1d63)) + ([9660aa9](https://code.castopod.org/adaures/castopod/commit/9660aa97c8ffd4fe61f3a388d52b9ac5dd8e1d63)) - replace website key for webpages in breadcrumb translate file - ([50e32ff](https://code.podlibre.org/podlibre/castopod/commit/50e32ff75636c1d4c5d945a267e884cb26ad7191)) + ([50e32ff](https://code.castopod.org/adaures/castopod/commit/50e32ff75636c1d4c5d945a267e884cb26ad7191)) - set episode duration translation to hardcoded english - ([c39efc9](https://code.podlibre.org/podlibre/castopod/commit/c39efc9489180662edcebd142d4476c0617ea97f)), - closes [#64](https://code.podlibre.org/podlibre/castopod/issues/64) + ([c39efc9](https://code.castopod.org/adaures/castopod/commit/c39efc9489180662edcebd142d4476c0617ea97f)), + closes [#64](https://code.castopod.org/adaures/castopod/issues/64) - set episode guid upon episode creation - ([ad8b153](https://code.podlibre.org/podlibre/castopod/commit/ad8b153f2a3b1a3b1751bf63785c4950e1516e6b)), - closes [#48](https://code.podlibre.org/podlibre/castopod/issues/48) + ([ad8b153](https://code.castopod.org/adaures/castopod/commit/ad8b153f2a3b1a3b1751bf63785c4950e1516e6b)), + closes [#48](https://code.castopod.org/adaures/castopod/issues/48) - update purgecss content path for php helper files - ([eb70bb4](https://code.podlibre.org/podlibre/castopod/commit/eb70bb4f7078ff347aeb8f5dcc7896311d289466)), - closes [#59](https://code.podlibre.org/podlibre/castopod/issues/59) + ([eb70bb4](https://code.castopod.org/adaures/castopod/commit/eb70bb4f7078ff347aeb8f5dcc7896311d289466)), + closes [#59](https://code.castopod.org/adaures/castopod/issues/59) - **install:** redirect to input baseUrl after instance config - ([2426af7](https://code.podlibre.org/podlibre/castopod/commit/2426af7de8c9d426aaf534ff17b67f71c2e9f374)), - closes [#53](https://code.podlibre.org/podlibre/castopod/issues/53) + ([2426af7](https://code.castopod.org/adaures/castopod/commit/2426af7de8c9d426aaf534ff17b67f71c2e9f374)), + closes [#53](https://code.castopod.org/adaures/castopod/issues/53) - **platforms:** display platform link only when visible is toggled on - ([6e503c8](https://code.podlibre.org/podlibre/castopod/commit/6e503c8d6182987e48892370623183f871bbd1c1)), - closes [#39](https://code.podlibre.org/podlibre/castopod/issues/39) + ([6e503c8](https://code.castopod.org/adaures/castopod/commit/6e503c8d6182987e48892370623183f871bbd1c1)), + closes [#39](https://code.castopod.org/adaures/castopod/issues/39) - sort episodic podcasts by season - ([d7b6794](https://code.podlibre.org/podlibre/castopod/commit/d7b6794f68f9a01fd606a407c6eb4c12d15dee74)) + ([d7b6794](https://code.castopod.org/adaures/castopod/commit/d7b6794f68f9a01fd606a407c6eb4c12d15dee74)) - update .htaccess for shared hosting config - ([2379826](https://code.podlibre.org/podlibre/castopod/commit/2379826352e2f4b5060910bf9f29268610102f2e)) + ([2379826](https://code.castopod.org/adaures/castopod/commit/2379826352e2f4b5060910bf9f29268610102f2e)) - update iso-369 language table seeder - ([0c90db4](https://code.podlibre.org/podlibre/castopod/commit/0c90db44c40de5af5b0b32b54489bda9424d9ef6)) + ([0c90db4](https://code.castopod.org/adaures/castopod/commit/0c90db44c40de5af5b0b32b54489bda9424d9ef6)) - **package.json:** update destination of postcss generation scripts - ([21413f8](https://code.podlibre.org/podlibre/castopod/commit/21413f8af3b8a0ac01d8c6f15bcd7a63e524e964)) + ([21413f8](https://code.castopod.org/adaures/castopod/commit/21413f8af3b8a0ac01d8c6f15bcd7a63e524e964)) - use slash instead of backslash to call layout - ([a80adb2](https://code.podlibre.org/podlibre/castopod/commit/a80adb22958fc0a38374cbce2d950a0042e699eb)) + ([a80adb2](https://code.castopod.org/adaures/castopod/commit/a80adb22958fc0a38374cbce2d950a0042e699eb)) ### Features - add alternate rss feed link tag to podcast page head - ([a973c09](https://code.podlibre.org/podlibre/castopod/commit/a973c097d54a3d0186c4079b9d4d3e81aae38505)), - closes [#35](https://code.podlibre.org/podlibre/castopod/issues/35) + ([a973c09](https://code.castopod.org/adaures/castopod/commit/a973c097d54a3d0186c4079b9d4d3e81aae38505)), + closes [#35](https://code.castopod.org/adaures/castopod/issues/35) - add analytics and unknown useragents - ([ec92e65](https://code.podlibre.org/podlibre/castopod/commit/ec92e65aa42e09b1df04600b52a0c679dfc494bb)) + ([ec92e65](https://code.castopod.org/adaures/castopod/commit/ec92e65aa42e09b1df04600b52a0c679dfc494bb)) - add breadcrumb in admin area - ([7fb1de2](https://code.podlibre.org/podlibre/castopod/commit/7fb1de2cf3c97c4cd7afe3bd71bbe66041786ecd)), - closes [#17](https://code.podlibre.org/podlibre/castopod/issues/17) + ([7fb1de2](https://code.castopod.org/adaures/castopod/commit/7fb1de2cf3c97c4cd7afe3bd71bbe66041786ecd)), + closes [#17](https://code.castopod.org/adaures/castopod/issues/17) - add french translation - ([196920d](https://code.podlibre.org/podlibre/castopod/commit/196920d62f1810b4c35f800d17d7f93627319091)) + ([196920d](https://code.castopod.org/adaures/castopod/commit/196920d62f1810b4c35f800d17d7f93627319091)) - add install wizard form to bootstrap database and create the first superadmin user - ([cba871c](https://code.podlibre.org/podlibre/castopod/commit/cba871c5df9f7120c44d9952456ebbd0d220669e)), - closes [#2](https://code.podlibre.org/podlibre/castopod/issues/2) + ([cba871c](https://code.castopod.org/adaures/castopod/commit/cba871c5df9f7120c44d9952456ebbd0d220669e)), + closes [#2](https://code.castopod.org/adaures/castopod/issues/2) - add ISO 3166 country codes - ([97cd94b](https://code.podlibre.org/podlibre/castopod/commit/97cd94b47494b66faf43fbbe0748872da80020a4)) + ([97cd94b](https://code.castopod.org/adaures/castopod/commit/97cd94b47494b66faf43fbbe0748872da80020a4)) - add map analytics, add episodes analytics, clean analytics page layout, translate countries - ([07eae83](https://code.podlibre.org/podlibre/castopod/commit/07eae83a00d860e149359fae67d549488403d88b)) + ([07eae83](https://code.castopod.org/adaures/castopod/commit/07eae83a00d860e149359fae67d549488403d88b)) - add npm for js dependencies + move src/ files to root folder - ([cbb83a6](https://code.podlibre.org/podlibre/castopod/commit/cbb83a6f308ac9357e9fb0cca5edae9d3fee5b48)) + ([cbb83a6](https://code.castopod.org/adaures/castopod/commit/cbb83a6f308ac9357e9fb0cca5edae9d3fee5b48)) - add pages table to store custom instance pages (eg. legal-notice, cookie policy, etc.) - ([9c224a8](https://code.podlibre.org/podlibre/castopod/commit/9c224a8ac6dd95f3c6c087a300fc8bac48e8090f)), - closes [#24](https://code.podlibre.org/podlibre/castopod/issues/24) + ([9c224a8](https://code.castopod.org/adaures/castopod/commit/9c224a8ac6dd95f3c6c087a300fc8bac48e8090f)), + closes [#24](https://code.castopod.org/adaures/castopod/issues/24) - add platform models - ([a333d29](https://code.podlibre.org/podlibre/castopod/commit/a333d291966229a909c0851fd8b890ed97c48ceb)) + ([a333d29](https://code.castopod.org/adaures/castopod/commit/a333d291966229a909c0851fd8b890ed97c48ceb)) - add platforms form in podcast settings - ([043f49c](https://code.podlibre.org/podlibre/castopod/commit/043f49c784bc007ca0fa756ca4ed2d3b08843ad9)) + ([043f49c](https://code.castopod.org/adaures/castopod/commit/043f49c784bc007ca0fa756ca4ed2d3b08843ad9)) - add platforms tables - ([ce59344](https://code.podlibre.org/podlibre/castopod/commit/ce5934419a516c9926dd3fd0ace3c11a95b60722)) + ([ce59344](https://code.castopod.org/adaures/castopod/commit/ce5934419a516c9926dd3fd0ace3c11a95b60722)) - add unique listeners analytics - ([3a49258](https://code.podlibre.org/podlibre/castopod/commit/3a4925816f3268230640525ad7af507aab8eecb9)) + ([3a49258](https://code.castopod.org/adaures/castopod/commit/3a4925816f3268230640525ad7af507aab8eecb9)) - add user permissions and basic groups to handle authorizations - ([d58e518](https://code.podlibre.org/podlibre/castopod/commit/d58e51874a4722921b75b0049117015c2380406e)), - closes [#3](https://code.podlibre.org/podlibre/castopod/issues/3) - [#18](https://code.podlibre.org/podlibre/castopod/issues/18) + ([d58e518](https://code.castopod.org/adaures/castopod/commit/d58e51874a4722921b75b0049117015c2380406e)), + closes [#3](https://code.castopod.org/adaures/castopod/issues/3) + [#18](https://code.castopod.org/adaures/castopod/issues/18) - create optimized & resized images upon upload - ([02e4441](https://code.podlibre.org/podlibre/castopod/commit/02e4441f98f27e9534e5b9b63279153d14632ccd)), - closes [#6](https://code.podlibre.org/podlibre/castopod/issues/6) + ([02e4441](https://code.castopod.org/adaures/castopod/commit/02e4441f98f27e9534e5b9b63279153d14632ccd)), + closes [#6](https://code.castopod.org/adaures/castopod/issues/6) - display legal disclaimer and warning on podcast import page - ([2f07992](https://code.podlibre.org/podlibre/castopod/commit/2f07992e5508b34b91f194eebfac80c51e80e90a)), - closes [#34](https://code.podlibre.org/podlibre/castopod/issues/34) + ([2f07992](https://code.castopod.org/adaures/castopod/commit/2f07992e5508b34b91f194eebfac80c51e80e90a)), + closes [#34](https://code.castopod.org/adaures/castopod/issues/34) - edit + delete podcast and episode - ([ac5f0c7](https://code.podlibre.org/podlibre/castopod/commit/ac5f0c732806e955c01e05b7867801bc938c6bd5)) + ([ac5f0c7](https://code.castopod.org/adaures/castopod/commit/ac5f0c732806e955c01e05b7867801bc938c6bd5)) - enhance admin ui with responsive design and ux improvements - ([2d44b45](https://code.podlibre.org/podlibre/castopod/commit/2d44b457a02205d2e7da258d7029b8bc5da39533)), - closes [#31](https://code.podlibre.org/podlibre/castopod/issues/31) - [#9](https://code.podlibre.org/podlibre/castopod/issues/9) + ([2d44b45](https://code.castopod.org/adaures/castopod/commit/2d44b457a02205d2e7da258d7029b8bc5da39533)), + closes [#31](https://code.castopod.org/adaures/castopod/issues/31) + [#9](https://code.castopod.org/adaures/castopod/issues/9) - enhance ui using javascript in admin area - ([c0e66d5](https://code.podlibre.org/podlibre/castopod/commit/c0e66d5f7012026e145d106f4d6bd3ba792a1b77)) + ([c0e66d5](https://code.castopod.org/adaures/castopod/commit/c0e66d5f7012026e145d106f4d6bd3ba792a1b77)) - import podcast from an rss feed url - ([9a5d5a1](https://code.podlibre.org/podlibre/castopod/commit/9a5d5a15b4945eb319da9e999c4ca60a0a4f6d2d)), - closes [#21](https://code.podlibre.org/podlibre/castopod/issues/21) + ([9a5d5a1](https://code.castopod.org/adaures/castopod/commit/9a5d5a15b4945eb319da9e999c4ca60a0a4f6d2d)), + closes [#21](https://code.castopod.org/adaures/castopod/issues/21) - set podcast / episode description in the pages description meta tag - ([1c4a504](https://code.podlibre.org/podlibre/castopod/commit/1c4a50442bea2d3449efce9c5ff1c80743152f55)), - closes [#44](https://code.podlibre.org/podlibre/castopod/issues/44) + ([1c4a504](https://code.castopod.org/adaures/castopod/commit/1c4a50442bea2d3449efce9c5ff1c80743152f55)), + closes [#44](https://code.castopod.org/adaures/castopod/issues/44) - update analytics so to meet IABv2 requirements - ([03e23a2](https://code.podlibre.org/podlibre/castopod/commit/03e23a28bf9b1b73fba55352c36a8cd6cc8ae729)), - closes [#10](https://code.podlibre.org/podlibre/castopod/issues/10) + ([03e23a2](https://code.castopod.org/adaures/castopod/commit/03e23a28bf9b1b73fba55352c36a8cd6cc8ae729)), + closes [#10](https://code.castopod.org/adaures/castopod/issues/10) - **cache:** add podcast and episode pages to cache + clear them after insert or update - ([da0f047](https://code.podlibre.org/podlibre/castopod/commit/da0f0472819007e02e5da37399f2377772c618b9)) + ([da0f047](https://code.castopod.org/adaures/castopod/commit/da0f0472819007e02e5da37399f2377772c618b9)) - **categories:** create model, entity, migrations and seeds - ([f73b042](https://code.podlibre.org/podlibre/castopod/commit/f73b042cc091be82abdbbca8992080875d526972)) + ([f73b042](https://code.castopod.org/adaures/castopod/commit/f73b042cc091be82abdbbca8992080875d526972)) - **devcontainer:** add devcontainer settings for dev environment - ([69e7266](https://code.podlibre.org/podlibre/castopod/commit/69e72667365247b63430dee88194e8f0d7c28edc)) + ([69e7266](https://code.castopod.org/adaures/castopod/commit/69e72667365247b63430dee88194e8f0d7c28edc)) - **episodes:** add create form and view pages for episode - ([f3b2c8b](https://code.podlibre.org/podlibre/castopod/commit/f3b2c8b84f3d93bef734e34dbe8ed729535e45e9)), - closes [#1](https://code.podlibre.org/podlibre/castopod/issues/1) + ([f3b2c8b](https://code.castopod.org/adaures/castopod/commit/f3b2c8b84f3d93bef734e34dbe8ed729535e45e9)), + closes [#1](https://code.castopod.org/adaures/castopod/issues/1) - **episodes:** add migrations, model and entity for episodes table - ([0444821](https://code.podlibre.org/podlibre/castopod/commit/044482174ede555ce19a2d8c6f48771cc8e7d27b)) + ([0444821](https://code.castopod.org/adaures/castopod/commit/044482174ede555ce19a2d8c6f48771cc8e7d27b)) - **podcast:** create a podcast using form - ([1202ba3](https://code.podlibre.org/podlibre/castopod/commit/1202ba3545f521097c60a6a2af95e70527cd1d34)) + ([1202ba3](https://code.castopod.org/adaures/castopod/commit/1202ba3545f521097c60a6a2af95e70527cd1d34)) - **podcast-form:** update routes and redirect to podcast page - ([12ce905](https://code.podlibre.org/podlibre/castopod/commit/12ce905799002dc9c07e6de092342d30ba9fd7d8)) + ([12ce905](https://code.castopod.org/adaures/castopod/commit/12ce905799002dc9c07e6de092342d30ba9fd7d8)) - **public-ui:** adapt public podcast and episode pages to wireframes - ([40a0535](https://code.podlibre.org/podlibre/castopod/commit/40a0535fc1bc12a24994b651f5e00b35995cbdda)), - closes [#30](https://code.podlibre.org/podlibre/castopod/issues/30) - [#13](https://code.podlibre.org/podlibre/castopod/issues/13) + ([40a0535](https://code.castopod.org/adaures/castopod/commit/40a0535fc1bc12a24994b651f5e00b35995cbdda)), + closes [#30](https://code.castopod.org/adaures/castopod/issues/30) + [#13](https://code.castopod.org/adaures/castopod/issues/13) - **rss:** generate rss feed from podcast entity - ([c815ecd](https://code.podlibre.org/podlibre/castopod/commit/c815ecd6640931fee0895f80908a3ddfac482666)) + ([c815ecd](https://code.castopod.org/adaures/castopod/commit/c815ecd6640931fee0895f80908a3ddfac482666)) - **users:** add myth-auth to handle users crud + add admin gateway only accessible by login - ([c63a077](https://code.podlibre.org/podlibre/castopod/commit/c63a077618c61b4cde7f25ffc650a4b0e1495f44)), - closes [#11](https://code.podlibre.org/podlibre/castopod/issues/11) + ([c63a077](https://code.castopod.org/adaures/castopod/commit/c63a077618c61b4cde7f25ffc650a4b0e1495f44)), + closes [#11](https://code.castopod.org/adaures/castopod/issues/11) - minor corrections to some tables - ([3bf9420](https://code.podlibre.org/podlibre/castopod/commit/3bf9420b5956a501b3b24405d243a71a928d6086)) + ([3bf9420](https://code.castopod.org/adaures/castopod/commit/3bf9420b5956a501b3b24405d243a71a928d6086)) - write id3v2 tags to episode's audio file - ([4651d01](https://code.podlibre.org/podlibre/castopod/commit/4651d01a84ff3ea8433a8ae26cfd750a1ec9e88d)) + ([4651d01](https://code.castopod.org/adaures/castopod/commit/4651d01a84ff3ea8433a8ae26cfd750a1ec9e88d)) ### Reverts - use basic input file for episodes audio files instead of button for better UX - ([d5f22fb](https://code.podlibre.org/podlibre/castopod/commit/d5f22fbb38c43d9b37df401eff655958a57cb40a)) + ([d5f22fb](https://code.castopod.org/adaures/castopod/commit/d5f22fbb38c43d9b37df401eff655958a57cb40a)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2b069532..b1291ae9 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,128 +1,162 @@ -# Contributor Covenant Code of Conduct +# Contributor Covenant 3.0 Code of Conduct ## Our Pledge -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity and -orientation. +We pledge to make our community welcoming, safe, and equitable for all. -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. +We are committed to fostering an environment that respects and promotes the +dignity, rights, and contributions of all individuals, regardless of +characteristics including race, ethnicity, caste, color, age, physical +characteristics, neurodiversity, disability, sex or gender, gender identity or +expression, sexual orientation, language, philosophy or religion, national or +social origin, socio-economic position, level of education, or other status. The +same privileges of participation are extended to everyone who participates in +good faith and in accordance with this Covenant. -## Our Standards +## Encouraged Behaviors -Examples of behavior that contributes to a positive environment for our -community include: +While acknowledging differences in social norms, we all strive to meet our +community's expectations for positive behavior. We also understand that our +words and actions may be interpreted differently than we intend based on +culture, background, or native language. -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -- Focusing on what is best not just for us as individuals, but for the overall - community +With these considerations in mind, we agree to behave mindfully toward each +other and act in ways that center our shared values, including: -Examples of unacceptable behavior include: +1. Respecting the **purpose of our community**, our activities, and our ways of + gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our + community**. -- The use of sexualized language or imagery, and sexual attention or advances of - any kind -- Trolling, insulting or derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or email address, - without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting +## Restricted Behaviors -## Enforcement Responsibilities +We agree to restrict the following behaviors in our community. Instances, +threats, and promotion of these behaviors are violations of this Code of +Conduct. -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. +1. **Harassment.** Violating explicitly expressed boundaries or engaging in + unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments + directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone’s personality or + behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered + inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality**. Sharing or acting on someone's personal or + private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm + toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or + pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content + you contribute. +3. **Promotional materials**. Sharing marketing or other commercial content in a + way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which + includes, links or describes any other restricted behaviors. + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their +best to collaborate. Not every conflict represents a code of conduct violation, +and this Code of Conduct reinforces encouraged behaviors and norms that can help +avoid conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a +possible violation, email us at [abuse@castopod.org](mailto:abuse@castopod.org). + +Community Moderators take reports of violations seriously and will make every +effort to respond in a timely manner. They will investigate all reports of code +of conduct violations, reviewing messages, logs, and recordings, or interviewing +witnesses and other participants. Community Moderators will keep investigation +and enforcement actions as transparent as possible while prioritizing safety and +confidentiality. In order to honor these values, enforcement actions are carried +out in private with the involved parties, but communicating to the whole +community may be part of a mutually agreed upon resolution. + +## Addressing and Repairing Harm + +If an investigation by the Community Moderators finds that this Code of Conduct +has been violated, the following enforcement ladder may be used to determine how +best to repair harm, based on the incident's impact on the individuals involved +and the community as a whole. Depending on the severity of a violation, lower +rungs on the ladder may be skipped. + +1. Warning + 1. Event: A violation involving a single incident or series of incidents. + 2. Consequence: A private, written warning from the Community Moderators. + 3. Repair: Examples of repair include a private written apology, + acknowledgement of responsibility, and seeking clarification on + expectations. +2. Temporarily Limited Activities + 1. Event: A repeated incidence of a violation that previously resulted in a + warning, or the first incidence of a more serious violation. + 2. Consequence: A private, written warning with a time-limited cooldown + period designed to underscore the seriousness of the situation and give + the community members involved time to process the incident. The cooldown + period may be limited to particular communication channels or interactions + with particular community members. + 3. Repair: Examples of repair may include making an apology, using the + cooldown period to reflect on actions and impact, and being thoughtful + about re-entering community spaces after the period is over. +3. Temporary Suspension + 1. Event: A pattern of repeated violation which the Community Moderators have + tried to address with warnings, or a single serious violation. + 2. Consequence: A private written warning with conditions for return from + suspension. In general, temporary suspensions give the person being + suspended time to reflect upon their behavior and possible corrective + actions. + 3. Repair: Examples of repair include respecting the spirit of the + suspension, meeting the specified conditions for return, and being + thoughtful about how to reintegrate with the community when the suspension + is lifted. +4. Permanent Ban + 1. Event: A pattern of repeated code of conduct violations that other steps + on the ladder have failed to resolve, or a violation so serious that the + Community Moderators determine there is no way to keep the community safe + with this person as a member. + 2. Consequence: Access to all community spaces, tools, and communication + channels is removed. In general, permanent bans should be rarely used, + should have strong reasoning behind them, and should only be resorted to + if working through other remedies has failed to change the behavior. + 3. Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the +ability of Community Managers to use their discretion and judgment, in keeping +with the best interests of our community. ## Scope This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed +an individual is officially representing the community in public or other +spaces. Examples of representing our community include using an official email +address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -[abuse@podlibre.org](mailto:abuse@podlibre.org). All complaints will be reviewed -and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, +permanently available at +[https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). +Contributor Covenant is stewarded by the Organization for Ethical Source and +licensed under CC BY-SA 4.0. To view a copy of this license, visit +[https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +For answers to common questions about Contributor Covenant, see the FAQ at +[https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). +Translations are provided at +[https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). +Additional enforcement and community guideline resources can be found at +[https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). +The enforcement ladder was inspired by the work of +[Mozilla’s code of conduct team](https://github.com/mozilla/inclusion). diff --git a/CONTRIBUTING-DEV.md b/CONTRIBUTING-DEV.md new file mode 100644 index 00000000..907d3ce1 --- /dev/null +++ b/CONTRIBUTING-DEV.md @@ -0,0 +1,437 @@ +# Setup your development environment + +## Introduction + +Castopod is a web app based on the `php` framework +[CodeIgniter 4](https://codeigniter.com). + +We use [Docker](https://www.docker.com/) to quickly setup a dev environment. A +`docker-compose.yml` and `Dockerfile` are included in the project's root folder +to help you kickstart your contribution. + +> You don't need any prior knowledge of Docker to follow the next steps. +> However, if you wish to use your own environment, feel free to do so! + +## Setup instructions + +### 1. Pre-requisites + +0. Install [Docker](https://docs.docker.com/get-docker). + +1. Clone the Castopod repository by running: + + ```bash + git clone https://code.castopod.org/adaures/castopod.git + ``` + +2. Create a `.env` file with the minimum required config to connect the app to + the database and use redis as a cache handler: + + ```ini + CI_ENVIRONMENT="development" + # If set to development, you must run `pnpm run dev` to start the static assets server + vite.environment="development" + + # By default, this is set to true in the app config. + # For development, this must be set to false as it is + # on a local environment + app.forceGlobalSecureRequests=false + + app.baseURL="http://localhost:8080/" + + admin.gateway="cp-admin" + auth.gateway="cp-auth" + + database.default.hostname="mariadb" + database.default.database="castopod" + database.default.username="castopod" + database.default.password="castopod" + database.default.DBPrefix="dev_" + + analytics.salt="DEV_ANALYTICS_SALT" + + cache.handler="redis" + cache.redis.host="redis" + + # You may not want to use redis as your cache handler + # Comment/remove the two lines above and uncomment + # the next line for file caching. + # ----------------------- + #cache.handler="file" + + ###################################### + # Media config + ###################################### + media.baseURL="http://localhost:8080/" + + # S3 + # Uncomment to store s3 objects using adobe/s3mock service + # ----------------------- + #media.fileManager="s3" + #media.s3.bucket="castopod" + #media.s3.endpoint="http://172.31.0.6:9090/" + #media.s3.pathStyleEndpoint=true + ``` + + > [!NOTE] + > You can tweak your environment by setting more environment variables in + > your custom `.env` file. See the `env` for examples or the + > [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) + > for more info. + +3. (for Docker desktop) Add the repository you've cloned to Docker desktop's + `Settings` > `Resources` > `File Sharing` + +### 2. (recommended) Develop inside the app container with VSCode + +If you're working in VSCode, you can take advantage of the `.devcontainer/` +folder. It defines a development environment (dev container) with preinstalled +requirements and VSCode extensions so you don't have to worry about them. All +required services will be loaded automagically! 🪄 + +1. Install the VSCode extension + [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +2. `Ctrl/Cmd + Shift + P` > `Open in container` + + > The VSCode window will reload inside the dev container. Expect several + > minutes during first load as it is building all necessary services. + + **Note**: The dev container will start by running Castopod's PHP server. + During development, you will have to start [Vite](https://vitejs.dev)'s dev + server for compiling the typescript code and styles: + + ```bash + # run Vite dev server + pnpm run dev + ``` + + If there is any issue with the PHP server not running, you can restart them + using the following commands: + + ```bash + # run Castopod server + php spark serve - 0.0.0.0 + ``` + +3. You're all set! 🎉 + + You're now **inside the dev container**, you may use the VSCode console + (`Terminal` > `New Terminal`) to run any command: + + ```bash + # PHP is installed + php -v + + # Composer is installed + composer -V + + # pnpm is installed + pnpm -v + + # git is installed + git version + ``` + +For more info, see +[Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers) + +### 3. Start hacking + +You're all set! Start working your magic by updating the project's files! Help +yourself to the +[CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for +more insights. + +To see your changes, go to: + +- `http://localhost:8080/` for the Castopod website +- `http://localhost:8080/cp-admin` for the Castopod admin: + - email: **admin@castopod.local** + - password: **castopod** + +- `http://localhost:8888/` for the phpmyadmin interface: + - username: **castopod** + - password: **castopod** + +### 2-alt. Develop outside the app container + +You do not wish to use the VSCode devcontainer? No problem! + +1. Start the Docker containers manually: + + Go to the project's root folder and run: + + ```bash + # starts all services declared in docker-compose.yml file + # -d option starts the containers in the background + docker-compose up -d + + # See all running processes (you should see 3 processes running) + docker-compose ps + + # Alternatively, you can check all docker processes + docker ps -a + + ``` + + > The `docker-compose up -d` command will boot 5 containers in the + > background: + > + > - `castopod_app`: a php based container with Castopod requirements + > installed + > - `castopod_redis`: a [redis](https://redis.io/) database to handle queries + > and pages caching + > - `castopod_mariadb`: a [mariadb](https://mariadb.org/) server for + > persistent data + > - `castopod_phpmyadmin`: a phpmyadmin server to visualize the mariadb + > database. + > - `castopod_s3`: a mock s3 server to work on the s3 fileManager + +2. Run any command inside the containers by prefixing them with + `docker-compose run --rm app`: + + ```bash + # use PHP + docker-compose run --rm app php -v + + # use Composer + docker-compose run --rm app composer -V + + # use pnpm + docker-compose run --rm app pnpm -v + + # use git + docker-compose run --rm app git version + ``` + +--- + +## Going Further + +### Install Castopod's dependencies + +1. Install php dependencies with [Composer](https://getcomposer.org/) + + ```bash + composer install + ``` + + > [!NOTE] + > The php dependencies aren't included in the repository. Composer will check + > the `composer.json` and `composer.lock` files to download the packages with + > the right versions. The dependencies will live under the `vendor/` folder. + > For more info, check out the + > [Composer documentation](https://getcomposer.org/doc/). + +2. Install JavaScript dependencies with [pnpm](https://pnpm.io/) + + ```bash + pnpm install + ``` + + > [!NOTE] + > The JavaScript dependencies aren't included in the repository. Pnpm will + > check the `package.json` and `pnpm-lock.yaml` files to download the + > packages with the right versions. The dependencies will live under the + > `node_module` folder. For more info, check out the + > [PNPM documentation](https://pnpm.io/motivation). + +3. Generate static assets: + + ```bash + # build all static assets at once + pnpm run build:static + + # build specific assets + pnpm run build:icons + pnpm run build:svg + ``` + + > [!NOTE] + > The static assets generated live under the `public/assets` folder, it + > includes JavaScript, styles, images, fonts, icons and svg files. + +### Initialize and populate database + +> [!TIP] +> You may skip this section if you go through the install wizard (go to +> `/cp-install`). + +1. Build the database with the migrate command: + + ```bash + # loads the database schema during first migration + php spark migrate -all + ``` + + You may need to undo the migration (rollback): + + ```bash + # rolls back database schema (deletes all tables and their content) + php spark migrate:rollback + ``` + +2. Populate the database with the required data: + + ```bash + # Populates all required data + php spark db:seed DevSeeder + ``` + + You may choose to add data separately: + + ```bash + # Populates all categories + php spark db:seed CategorySeeder + + # Populates all Languages + php spark db:seed LanguageSeeder + + # Adds a superadmin with [admin@castopod.local / castopod] credentials + php spark db:seed DevSuperadminSeeder + ``` + +3. (optional) Populate the database with test data: + - Populate with fake podcast analytics: + + ```bash + php spark db:seed FakePodcastsAnalyticsSeeder + ``` + + - Populate with fake website analytics: + + ```bash + php spark db:seed FakeWebsiteAnalyticsSeeder + ``` + +### Useful docker / docker-compose commands + +- Monitor the app container: + +```bash +docker-compose logs --tail 50 --follow --timestamps app +``` + +- Interact with the Redis server using included redis-cli command: + +```bash +docker exec -it castopod_redis redis-cli +``` + +- Monitor the Redis container: + +```bash +docker-compose logs --tail 50 --follow --timestamps redis +``` + +- Monitor the mariadb container: + +```bash +docker-compose logs --tail 50 --follow --timestamps mariadb +``` + +- Monitor the phpmyadmin container: + +```bash +docker-compose logs --tail 50 --follow --timestamps phpmyadmin +``` + +- Restart docker containers: + +```bash +docker-compose restart +``` + +- Destroy all containers, opposite of `up` command: + +```bash +docker-compose down +``` + +- Rebuild app container: + +```bash +docker-compose build app +``` + +Check [Docker](https://docs.docker.com/engine/reference/commandline/docker/) and +[docker-compose](https://docs.docker.com/compose/reference/) documentations for +more insights. + +### Updating Documentation + +Castopod's documentation is written in Markdown and uses the Astro Starlight +framework. To update Castopod's documentation, including the Getting Started +guide and User Guide: + +1. Change directories to the `docs` directory and install the dependencies: + + ```bash + cd docs/ + pnpm i + ``` + +2. Start the documentation development server: + + ```bash + pnpm run dev --host + ``` + +3. The documentation development server runs on port 4321. In your browser visit + `http://localhost:4321/docs`. If the page displays a 404 Not Found error, + click on the Castopod logo in the upper left hand corner of the page and the + documentation should load. + +4. Edit the Markdown files with your documentation updates. The Astro Starlight + development server will automatically update each time you save a change. + +## Known issues + +### Allocation failed - JavaScript heap out of memory + +This happens when running `pnpm install`. + +👉 By default, docker might not have access to enough RAM. Allocate more memory +and run `pnpm install` again. + +### (Linux) Files created inside container are attributed to root locally + +You may use Linux user namespaces to fix this on your machine: + +> [!NOTE] +> Replace "username" with your local username + +1. Go to `/etc/docker/daemon.json` and add: + + ```json + { + "userns-remap": "username" + } + ``` + +2. Configure the subordinate uid/guid: + + ```bash + # in /etc/subuid + username:1000:1 + username:100000:65536 + ``` + + ```bash + # in /etc/subgid + username:1000:1 + username:100000:65536 + ``` + +3. Restart Docker: + + ```bash + sudo systemctl restart docker + ``` + +4. That's it! Now, the root user in the container will be mapped to the user on + your local machine, no more permission issues! 🎉 + +You can check +[this great article](https://www.jujens.eu/posts/en/2017/Jul/02/docker-userns-remap/) +to know more about how it works. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f2eba802..a3468537 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,16 @@ -# Contributing to Castopod Host +# Contributing to Castopod -Love Castopod Host and want to help? Thanks so much, there's something to do for +Love Castopod and want to help? Thanks so much, there's something to do for everybody! +> [!NOTE] +> Castopod follows the [all contributors](https://allcontributors.org/) +> specification in an effort to **recognize any kind of contribution**, not just +> code! +> If you've made a contribution and do not appear in the +> [contributors](../index.md#contributors-✨) list, please +> [let us know](../index.md#contact) so we can correct our mistake! 🙂 + Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. @@ -11,17 +19,34 @@ developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. -⚠️ Note that **any** contribution made on a repository other than -[the original repository](https://code.podlibre.org/podlibre/castopod-host) will -not be accepted. +## Translating Castopod + +We use [Crowdin](https://translate.castopod.org/) to manage translation files +for [Castopod](https://code.castopod.org/), the +[documentation](https://docs.castopod.org/) and the +[landing](https://castopod.org/) websites. + +Whether you'd like to correct a translation error, validate new translations or +include your language to Castopod, head into the +[crowdin project](https://translate.castopod.org/) to get started. + +> [!NOTE] +> To prevent degrading user experience, new languages are included to Castopod +> when they reach a certain threshold (~90%). ## Using the issue tracker -The [issue tracker](https://code.podlibre.org/podlibre/castopod-host/-/issues) -is the preferred channel for [bug reports](#bug-reports), +The [issue tracker](https://code.castopod.org/adaures/castopod/-/issues) is the +preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests). +## ⚠️ Security issues and vulnerabilities + +If you encounter any security issue or vulnerability in the Castopod source, +please contact us directly by email at +[security@castopod.org](mailto:security@castopod.org) + ## Bug reports A bug is a _demonstrable problem_ that is caused by the code in the repository. @@ -45,8 +70,9 @@ your environment? What steps will reproduce the issue? What browser(s) and OS experience the problem? What would you expect to be the outcome? All these details will help people to fix any potential bugs. -> [Issue templates](https://docs.gitlab.com/ee/user/project/description_templates.html#using-the-templates) -> have been created for this project. You may use them to help you follow those +> [!NOTE] +> [Issue templates](https://docs.gitlab.com/ee/user/project/description_templates.html#using-the-templates) have +> been created for this project. You may use them to help you follow those > guidelines. ## Feature requests @@ -72,33 +98,33 @@ accurate comments, etc.) and any other requirements (such as test coverage). Adhering to the following process is the best way to get your work included in the project: -1. [Fork](https://docs.gitlab.com/ee/gitlab-basics/fork-project.html) the - project, clone your fork, and configure the remotes: +1. [Fork](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html) + the project, clone your fork, and configure the remotes: -```bash -# Clone your fork of the repo into the current directory -git clone https://code.podlibre.org//castopod-host.git + ```bash + # Clone your fork of the repo into the current directory + git clone https://code.castopod.org//castopod.git -# Navigate to the newly cloned directory -cd castopod-host + # Navigate to the newly cloned directory + cd castopod -# Assign the original repo to a remote called "upstream" -git remote add upstream https://code.podlibre.org/podlibre/castopod-host.git -``` + # Assign the original repo to a remote called "upstream" + git remote add upstream https://code.castopod.org/adaures/castopod.git + ``` 2. If you cloned a while ago, get the latest changes from upstream: -```bash -git checkout main -git pull upstream main -``` + ```bash + git checkout main + git pull upstream main + ``` 3. Create a new topic branch (off the `main` branch) to contain your feature, change, or fix: -```bash -git checkout -b -``` + ```bash + git checkout -b + ``` 4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](https://conventionalcommits.org/) or your @@ -108,22 +134,23 @@ git checkout -b 5. Locally merge (or rebase) the upstream dev branch into your topic branch: -```bash -git pull [--rebase] upstream main -``` + ```bash + git pull [--rebase] upstream main + ``` 6. Push your topic branch up to your fork: -```bash -git push origin -``` + ```bash + git push origin + ``` 7. [Open a Pull Request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html#new-merge-request-from-a-fork) with a clear title and description. -**IMPORTANT**: By submitting a patch, you agree to allow the project owners to -license your work under the terms of the -[GNU AGPLv3](https://code.podlibre.org/podlibre/castopod-host/-/blob/main/LICENSE). +> [!IMPORTANT] +> By submitting a patch, you agree to allow the project owners to license your +> work under the terms of the +> [GNU AGPLv3](https://code.castopod.org/adaures/castopod/-/blob/develop/LICENSE.md). ## Collaborating guidelines diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 93371ef5..97175ffd 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -1,66 +1,26 @@ -# Castopod Host dependencies +# Castopod dependencies -Castopod Host uses the following components: +Castopod uses the following components: -PHP Dependencies: +## PHP Dependencies -- [CodeIgniter 4](https://codeigniter.com) - ([MIT License](https://codeigniter.com/user_guide/license.html)) -- [WhichBrowser/Parser-PHP](https://github.com/WhichBrowser/Parser-PHP) - ([MIT License](https://github.com/WhichBrowser/Parser-PHP/blob/master/LICENSE)) -- [GeoIP2 PHP API](https://github.com/maxmind/GeoIP2-php) - ([Apache License 2.0](https://github.com/maxmind/GeoIP2-php/blob/master/LICENSE)) -- [getID3](https://github.com/JamesHeinrich/getID3) - ([GNU General Public License v3](https://github.com/JamesHeinrich/getID3/blob/2.0/licenses/license.gpl-30.txt)) -- [myth-auth](https://github.com/lonnieezell/myth-auth) - ([MIT license](https://github.com/lonnieezell/myth-auth/blob/develop/LICENSE.md)) -- [commonmark](https://commonmark.thephpleague.com/) - ([BSD 3-Clause "New" or "Revised" License](https://github.com/thephpleague/commonmark/blob/latest/LICENSE)) -- [phpdotenv](https://github.com/vlucas/phpdotenv) - ([ BSD-3-Clause License ](https://github.com/vlucas/phpdotenv/blob/master/LICENSE)) -- [HTML To Markdown for PHP](https://github.com/thephpleague/html-to-markdown) - ([MIT License](https://github.com/thephpleague/html-to-markdown/blob/master/LICENSE)) -- [opawg/user-agents-php](https://github.com/opawg/user-agents-php) - ([MIT License](https://github.com/podlibre/user-agents-php/blob/main/LICENSE)) -- [podlibre/ipcat](https://github.com/podlibre/ipcat) - ([GNU General Public License v3.0](https://github.com/podlibre/ipcat/blob/master/LICENSE)) -- [podlibre/podcast-namespace](https://code.podlibre.org/podlibre/podcastnamespace) - ([MIT License](https://code.podlibre.org/podlibre/podcastnamespace/-/blob/master/LICENSE)) -- [phpseclib](https://phpseclib.com/) - ([MIT License](https://github.com/phpseclib/phpseclib/blob/master/LICENSE)) -- [codeigniter4-uuid](https://github.com/michalsn/codeigniter4-uuid) - ([MIT License](https://github.com/michalsn/codeigniter4-uuid/blob/develop/LICENSE)) -- [essence](https://github.com/essence/essence) - ([The FreeBSD License](https://github.com/essence/essence/blob/master/LICENSE.txt)) +PHP dependencies can be found in the [composer.json](./composer.json) file. -Javascript dependencies: +## Javascript dependencies -- [rollup](https://rollupjs.org/) - ([MIT License](https://github.com/rollup/rollup/blob/master/LICENSE.md)) -- [tailwindcss](https://tailwindcss.com/) - ([MIT License](https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE)) -- [ProseMirror](https://prosemirror.net/) - ([MIT License](https://github.com/ProseMirror/prosemirror/blob/master/LICENSE)) -- [amCharts 4](https://github.com/amcharts/amcharts4) - ([Free amCharts license](https://github.com/amcharts/amcharts4/blob/master/dist/script/LICENSE)) -- [Choices.js](https://joshuajohnson.co.uk/Choices/) - ([MIT License](https://github.com/jshjohnson/Choices/blob/master/LICENSE)) -- [flatpickr](https://flatpickr.js.org/) - ([MIT License](https://github.com/flatpickr/flatpickr/blob/master/LICENSE.md)) -- [popperjs](https://popper.js.org/) - ([MIT License](https://github.com/popperjs/popper-core/blob/master/LICENSE.md)) +Javascript dependencies can be found in the [package.json](./package.json) file. -Other: +## Other dependencies - [Kumbh Sans](https://fonts.google.com/specimen/Kumbh+Sans) ([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)) -- [Montserrat](https://fonts.google.com/specimen/Montserrat) +- [Inter](https://fonts.google.com/specimen/Inter) ([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)) - [RemixIcon](https://remixicon.com/) ([Apache License 2.0](https://github.com/Remix-Design/RemixIcon/blob/master/License)) -- [OPAWG/User agent list](https://github.com/opawg/user-agents) +- [OPAWG/User agent list](https://github.com/opawg/user-agents-v2) ([by Open Podcast Analytics Working Group](https://github.com/opawg)) - ([MIT license](https://github.com/opawg/user-agents/blob/master/LICENSE)) + ([MIT license](https://github.com/opawg/user-agents-v2/blob/master/LICENSE)) - [OPAWG/podcast-rss-useragents](https://github.com/opawg/podcast-rss-useragents) ([by Open Podcast Analytics Working Group](https://github.com/opawg)) ([MIT license](https://github.com/opawg/podcast-rss-useragents/blob/master/LICENSE)) diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 9eb3536d..00000000 --- a/Dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -#################################################### -# Castopod Host development Docker file -#################################################### -# ⚠️ NOT optimized for production -# should be used only for development purposes -#--------------------------------------------------- -FROM php:8.0-fpm - -LABEL maintainer="Yassine Doghri " - -COPY . /castopod-host -WORKDIR /castopod-host - -# Install composer -COPY --from=composer:2 /usr/bin/composer /usr/bin/composer - -# Install server requirements -RUN apt-get update \ - # gnupg to sign commits with gpg - && apt-get install --yes --no-install-recommends gnupg \ - # npm through the nodejs package - && curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \ - && apt-get update \ - && apt-get install --yes --no-install-recommends nodejs \ - # update npm - && npm install --global npm@7 \ - && apt-get update \ - && apt-get install --yes --no-install-recommends \ - git \ - openssh-client \ - vim \ - # cron for scheduled tasks - cron \ - # unzip used by composer - unzip \ - # required libraries to install php extensions using - # https://github.com/mlocati/docker-php-extension-installer (included in php's docker image) - libicu-dev \ - libpng-dev \ - libjpeg-dev \ - zlib1g-dev \ - libzip-dev \ - # intl for Internationalization - && docker-php-ext-install intl \ - && docker-php-ext-install zip \ - # gd for image processing - && docker-php-ext-configure gd --with-jpeg \ - && docker-php-ext-install gd \ - # redis extension for cache - && pecl install -o -f redis \ - && rm -rf /tmp/pear \ - && docker-php-ext-enable redis \ - # mysqli for database access - && docker-php-ext-install mysqli \ - && docker-php-ext-enable mysqli \ - # configure php - && echo "file_uploads = On\n" \ - "memory_limit = 512M\n" \ - "upload_max_filesize = 500M\n" \ - "post_max_size = 512M\n" \ - "max_execution_time = 300\n" \ - > /usr/local/etc/php/conf.d/uploads.ini \ diff --git a/GDPR.txt b/GDPR.txt new file mode 100644 index 00000000..a7336bac --- /dev/null +++ b/GDPR.txt @@ -0,0 +1,83 @@ +# This file lists processing purposes and the personal data gathered by +# Castopod. +# It is intended for hosting providers who want to provide a service +# based on Castopod, helping them to comply with GDPR requirements. Note +# that the services powered by Castopod may collect more data, HTTP logs +# in particular. As a hosting provider, you must inform your users of their +# rights and how their data are used and protected. + +purpose: + Deduplicate number of audio file downloads made by the same listener + for analytics purposes +lawfulness: legitimate interest + +data: (User IP address + Browser User Agent) +required: yes +visibility: none +description: + In order to produce analytics data comparable to the podcasting + ecosystem standards, the User IP address (REMOTE_ADDR) with the + browser User Agent (HTTP_USER_AGENT) are stored when an audio file + is downloaded. +mitigation: + The data (User IP address + Browser User Agent) is never stored in plain + format. + The data is concatenated with a cryptographic salt, the current date, + and the podcast or episode IDs. + The data is hashed (using sha1) after being concatenated and before + being stored. + The data is stored in a cache database (eg. Redis). + The data expires every day at midnight (server time). + +purpose: Connect users to their accounts +lawfulness: legitimate interest + +data: username +required: yes +visibility: authenticated users +description: + The username is used to identify users during the login process. + The username is only required for users accessing the admin area. +mitigation: + The username does not have to be a real or known identity. + +data: user e-mail address +required: yes +visibility: administrators +description: + The e-mail address is used for administrative purposes, to identify users + during the login process and in case of forgotten password. + +data: password +required: yes +visibility: private +description: + The password is used to check the identity of users during the login + process. +mitigation: + Only hashes (using the Argon2 key derivation function) of the passwords + are stored in the database (but they transit over the network). + +purpose: Claim ownership of a podcast +lawfulness: legitimate interest + +data: Podcast e-mail address +required: yes +visibility: public +description: + The podcast e-mail address is used to claim podcast ownership on other + platforms (such as Apple Podcasts). +mitigation: + The e-mail can be generic. + +purpose: Grant access to premium content +lawfulness: legitimate interest + +data: Subscriber's email address +required: yes +visibility: administrators +description: + The subscriber's e-mail address is used to provide credentials for + listening to premium content. +mitigation: + The e-mail can be generic. diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index 826458f3..00000000 --- a/INSTALL.md +++ /dev/null @@ -1,123 +0,0 @@ -# How to install Castopod Host - -_Castopod Host_ was thought-out to be easy to install. Whether using dedicated -or shared hosting, you can install it on most PHP-MySQL compatible web servers. - -## Table of contents - -- [Install instructions](#install-instructions) - - [0. Pre-requisites](#0-pre-requisites) - - [(recommended) Install Wizard](#recommended-install-wizard) - - [(alternative) Manual configuration](#alternative-manual-configuration) -- [Web Server Requirements](#web-server-requirements) - - [PHP v8.0 or higher](#php-v80-or-higher) - - [MySQL compatible database](#mysql-compatible-database) - - [Privileges](#privileges) - - [(Optional) Other recommendations](#optional-other-recommendations) -- [Security concerns](#security-concerns) - -## Install instructions - -### 0. Pre-requisites - -0. Get a Web Server with requirements installed -1. Create a MySQL database for Castopod Host with a user having access and - modification privileges (for more info, see - [Web Server Requirements](#web-server-requirements)). -2. Activate HTTPS on your domain with an _SSL certificate_. -3. Download and unzip the latest - [Castopod Host Package](https://code.podlibre.org/podlibre/castopod-host/-/releases) - onto the web server if you haven’t already. - - ⚠️ Set the web server document root to the `public/` sub-folder. -4. Add a cron task on your web server to run every minute (replace the paths - accordingly): - - ```php - * * * * * /path/to/php /path/to/castopod-host/public/index.php scheduled-activities - ``` - - > ⚠️ Social features will not work properly if you do not set the task. It is - > used to broadcast social activities to the fediverse. - -### (recommended) Install Wizard - -1. Run the Castopod Host install script by going to the install wizard page - (`https://your_domain_name.com/cp-install`) in your favorite web browser. -2. Follow the instructions on your screen. -3. Start podcasting! - -> **Note:** -> -> The install script writes a `.env` file in the package root. If you cannot go -> through the install wizard, you can -> [create and update the `.env` file manually](#alternative-manual-configuration). - -### (alternative) Manual configuration - -1. Rename the `.env.example` file to `.env` and update the default values with - your own. -2. Upload the `.env` file to the Castopod Host Package root on your server. -3. Go to `/cp-install` to finish the install process. -4. Start podcasting! - -## Web Server Requirements - -### PHP v8.0 or higher - -PHP version 8.0 or higher is required, with the following extensions installed: - -- [intl](https://php.net/manual/en/intl.requirements.php) -- [libcurl](https://php.net/manual/en/curl.requirements.php) -- [mbstring](https://php.net/manual/en/mbstring.installation.php) -- [gd](https://www.php.net/manual/en/image.installation.php) - -Additionally, make sure that the following extensions are enabled in your PHP: - -- json (enabled by default - don't turn it off) -- xml (enabled by default - don't turn it off) -- [mysqlnd](https://php.net/manual/en/mysqlnd.install.php) - -### MySQL compatible database - -> We recommend using [MariaDB](https://mariadb.org). - -You will need the server hostname, database name, username and password to -complete the installation process. If you do not have these, please contact your -server administrator. - -> NB. Castopod Host only works with supported MySQL compatible databases. It -> will break with MySQL v5.6 for example as its end of life was on February -> 5, 2021. - -#### Privileges - -User must have at least these privileges on the database for Castopod Host to -work: `ALTER`, `DELETE`, `EXECUTE`, `INDEX`, `INSERT`, `SELECT`, `UPDATE`. - -### (Optional) Other recommendations - -- Redis for better cache performances. -- CDN for static files caching and better performances. -- e-mail gateway for lost passwords. - -## Security concerns - -Castopod Host is built on top of Codeigniter, a PHP framework that encourages -[good security practices](https://codeigniter.com/user_guide/concepts/security.html). - -To maximize your instance safety and prevent any malicious attack, we recommend -you update all your Castopod Host files permissions after installation (to avoid -any permission error): - -- `writable/` folder must be **readable** and **writable**. -- `public/media/` folder must be **readable** and **writable**. -- any other file must be set to **readonly**. - -For instance, if you are using Apache or NGINX with Ubuntu you may do the -following: - -```bash -sudo chown -R root:root /path/to/castopod-host -sudo chown -R www-data:www-data /path/to/castopod-host/writable -sudo chown -R www-data:www-data /path/to/castopod-host/public/media -``` diff --git a/README.md b/README.md index ba68c34b..6460720c 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,191 @@ -

- Castopod Host -

- -> ⚠️ **Castopod Host is in alpha version**. It is still under heavy development -> and may not be 100% stable as new features are being worked on. - -_Castopod Host_ is a free and open-source podcast hosting solution made for -podcasters who want engage and interact with their audience. - -Create, upload, publish, interact with your followers and get comprehensive -audience measurements that respect your listeners privacy. - -Whether you choose to install it on your own server or have it hosted by a -professional, all your data and analytics belong to you and you only! - -
- Castopod Mascot +
+

+ + Castopod + +

-You may find Castopod Host's source code on the -[original repository](https://code.podlibre.org/podlibre/castopod-host) or, -alternatively, on the -[github repository (mirror)](https://github.com/podlibre/castopod-host). +
-## Install / Update +[![release-badge]][release] [![license-badge]][license] [![crowdin-badge]][crowdin] [![contributions-badge]][contributions] [![semantic-release-badge]][semantic-release] [![discord-badge]][discord] [![stars-badge]][stars] -To install or update Castopod Host on your PHP/MySQL server: +
-- Download - [Castopod Host's latest Package (zip or tar.gz)](https://code.podlibre.org/podlibre/castopod-host/-/releases): +Castopod is a free and open-source podcast hosting solution made for podcasters +who want engage and interact with their audience. -- Follow one of the procedures on: +## Getting started - - [“How to **install** Castopod Host”](./INSTALL.md) - - or [“How to **update** Castopod Host”](./UPDATE.md) +Castopod comes pre-packaged with all the required static assets and +dependencies, you may download and install it by checking out the +[getting started page](https://castopod.org/getting-started/)! -## Documentation +## Security issues and vulnerabilities -You can check Castopod Host's documentation for -[setting up a development environment](./docs/setup-development.md). +If you encounter any security issue or vulnerability in the Castopod source, +please contact us directly by email at +[security@castopod.org](mailto:security@castopod.org) ## Contributing -Love Castopod Host and would like to help? Check out the -[contribution guidelines](./CONTRIBUTING.md) for this project, everything should -be there! +Contributions are always welcome! -⚠️ Note that **any** contribution made on a repository other than -[the original repository](https://code.podlibre.org/podlibre/castopod-host) will -not be accepted. +See the [contribution guidelines](./CONTRIBUTING.md) for ways to get started. -## Support +> [!Important] +> **Any** contribution made on a repository other than +> [the original repository](https://code.castopod.org/adaures/castopod) will not +> be accepted. + +## Contributors ✨ + +Thanks goes to these wonderful people +([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Yassine Doghri
Yassine Doghri

💻 🐛 📖 👀 🚧 🖋 🎨 ️️️️♿️ 🌍 💬 🧑‍🏫 🚇 🤔 📆 📝
Benjamin Bellamy
Benjamin Bellamy

💻 🐛 👀 🖋 🌍 💬 🚇 🤔 📝 📆 📢
Ola Hneini
Ola Hneini

💻 👀 📖 🚧 💬 🤔
Romain de Laage
Romain de Laage

💻 🚇 📖 🌍 🤔
Lyonel Bernard
Lyonel Bernard

🐛 💬 🔊 🤔
Christopher Lagonick-Weitzel
Christopher Lagonick-Weitzel

🐛 💬 🔊 🤔
Ernesto Acosta
Ernesto Acosta

🐛 🔊 🌍 💬 🤔
Ewen
Ewen

🌍 🤔 💻
Bastien Luneteau
Bastien Luneteau

💻 🐛
Cécile Ricordeau
Cécile Ricordeau

🎨
Patryk Miś
Patryk Miś

🌍
Marcin Lewandowski
Marcin Lewandowski

🐛 🤔
Sebastian Janik
Sebastian Janik

💻
Patryk Karczmarczyk
Patryk Karczmarczyk

💻
denis d
denis d

🐛 🤔
Douglas Kastle
Douglas Kastle

🐛 🤔
cExplorer
cExplorer

🐛 🌍
ImaCrea
ImaCrea

🐛 🤔
Jonas S
Jonas S

💻
LEFEBVRE Yann
LEFEBVRE Yann

🐛
Sebastian Späth
Sebastian Späth

🐛 🤔
rocky III
rocky III

🐛
Hermann Josef Eckl
Hermann Josef Eckl

🐛
Delhaye Cyrille
Delhaye Cyrille

🐛 🤔
João Leandro
João Leandro

🌍 🤔
Angelos Chouvardas
Angelos Chouvardas

🌍
Eivind
Eivind

🌍
forght
forght

🌍
glottis0q
glottis0q

🌍
ButterflyOfFire
ButterflyOfFire

🌍
Lucian I. Last
Lucian I. Last

🌍
LuuzViir
LuuzViir

🌍
CTHTC
CTHTC

🌍
Russian Retro
Russian Retro

🌍
Marek L'ach
Marek L'ach

🌍
GunChleoc
GunChleoc

🌍
GabiSnow
GabiSnow

🌍
bendaha
bendaha

🌍
Samuel Roland
Samuel Roland

🌍
Dimitri Regnier
Dimitri Regnier

🤔
irithys
irithys

🌍
Sergi
Sergi

🌍
Andreas Olsson
Andreas Olsson

🌍
leonfrom
leonfrom

🌍
agentcobra
agentcobra

🌍
Alessandro
Alessandro

🌍
liimee
liimee

🌍
Ahmed Sabouni
Ahmed Sabouni

🌍
KrzysztofDomanczyk
KrzysztofDomanczyk

💻
Guy Martin
Guy Martin

🐛 💻
Paul Cutler
Paul Cutler

📖 💬 🤔
Nate Ritter
Nate Ritter

💻
+ + + + + + +This project follows the +[all-contributors](https://github.com/all-contributors/all-contributors) +specification. Contributions of any kind welcome! + +## Contact You may reach us for help or ask any question you have on: - [Discord](https://castopod.org/discord) (for direct interaction with developers and the community) +- [Issue tracker](https://code.castopod.org/adaures/castopod/-/issues) (for + feature requests & bug reports) Alternatively, you can follow us on social media platforms to get news about Castopod: - [podlibre.social](https://podlibre.social/@Castopod) (Mastodon instance) -- [Twitter](https://twitter.com/castopod) +- [Bluesky](https://bsky.app/profile/castopod.org) +- [LinkedIn](https://linkedin.com/company/castopod) - [Facebook](https://www.facebook.com/castopod) ## Sponsors -[Castopod](https://nlnet.nl/project/Castopod/) was funded through the -[NGI0 Discovery](https://nlnet.nl/discovery/) Fund under grant agreement -Nº 825322. +The ongoing development of Castopod is made possible with the support of its +backers. If you'd like to help, please consider +[sponsoring Castopod's development](https://opencollective.com/castopod/contribute). -The fund was established by NLnet with financial support from the European -Commission's [Next Generation Internet](https://www.ngi.eu/) programme, under -the aegis of DG Communications Networks, Content and Technology. + + + + + + + +
+ Ad Aures + + NLnet Logo +
+ +## License + +[GNU Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/) + +Copyright © 2020-present, [Ad Aures](https://adaures.com/). + +[release]: https://code.castopod.org/adaures/castopod/-/releases +[release-badge]: + https://img.shields.io/gitlab/v/release/2?color=brightgreen&gitlab_url=https%3A%2F%2Fcode.castopod.org%2F&include_prereleases&label=release +[license]: https://code.castopod.org/adaures/castopod/-/blob/beta/LICENSE.md +[license-badge]: + https://img.shields.io/github/license/ad-aures/castopod?color=blue +[contributions]: https://code.castopod.org/adaures/castopod/-/issues +[contributions-badge]: + https://img.shields.io/badge/contributions-welcome-brightgreen.svg +[semantic-release]: https://github.com/semantic-release/semantic-release +[semantic-release-badge]: + https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg +[discord]: https://castopod.org/discord +[discord-badge]: https://img.shields.io/badge/chat-on%20discord-7389D8 +[stars]: https://github.com/ad-aures/castopod/stargazers +[stars-badge]: + https://img.shields.io/github/stars/ad-aures/castopod?style=social +[crowdin]: https://translate.castopod.org/project/castopod +[crowdin-badge]: https://badges.crowdin.net/castopod/localized.svg diff --git a/UPDATE.md b/UPDATE.md deleted file mode 100644 index fe8923ae..00000000 --- a/UPDATE.md +++ /dev/null @@ -1,95 +0,0 @@ -# How to update Castopod Host - -After installing _Castopod Host_, you may want to update your instance to the -latest version in order to enjoy the latest features ✨, bug fixes 🐛 and -performance improvements ⚡. - -## Table of contents - -- [Manual update instructions](#manual-update-instructions) -- [Automatic update instructions](#automatic-update-instructions) -- [Frequently asked questions (FAQ)](#frequently-asked-questions-faq) - - [Where can I find my _Castopod Host_ version?](#where-can-i-find-my-castopod-host-version) - - [I haven't updated my instance in a long time… What should I do?](#i-havent-updated-my-instance-in-a-long-time-what-should-i-do) - - [Should I make a backup before updating?](#should-i-make-a-backup-before-updating) - -## Manual update instructions - -1. Go to the - [releases page](https://code.podlibre.org/podlibre/castopod-host/-/releases) - and see if your instance is up to date with the latest _Castopod Host_ - version - - - cf. - [Where can I find my _Castopod Host_ version?](#where-can-i-find-my-castopod-host-version) - -2. Download the latest release package named `Castopod Host Package`, you may - choose between the `zip` or `tar.gz` archives - - - ⚠️ Make sure you download the Castopod Host Package and **NOT** the Source - Code - -3. On your server: - - - Remove all files except `.env` and `public/media` - - Copy the new files from the downloaded package into your server - - Note: you may need to reset files permissions as during the install - process. Check - [Security Concerns section in INSTALL.md](./INSTALL.md#security-concerns). - -4. Alpha releases may come with additional update instructions (see - [releases page](https://code.podlibre.org/podlibre/castopod-host/-/releases)). - They are usually database migration scripts in `.sql` format to update your - database schema. - - - 👉 Make sure you run the scripts on your phpmyadmin panel or using command - line to update the database along with the package files! - - cf. - [I haven't updated my instance in a long time… What should I do?](#i-havent-updated-my-instance-in-a-long-time-what-should-i-do) - -5. If you are using redis, clear your cache. -6. ✨ Enjoy your fresh instance, you're all done! - -## Automatic update instructions - -> Coming soon... 👀 - -## Frequently asked questions (FAQ) - -### Where can I find my _Castopod Host_ version? - -Go to your _Castopod Host_ admin panel, the version is displayed on the bottom -right corner. - -Alternatively, you can find the version in the `app > Config > Constants.php` -file. - -### I haven't updated my instance in a long time… What should I do? - -No problem! Just get the latest release as described above. Only, when going -through the release instructions (4), perform them sequentially, from the oldest -to the newest. - -> You may want to backup your instance depending on how long you haven't updated -> _Castopod Host_. - -For example, if you're on `v1.0.0-alpha.42` and would like to upgrade to -`v1.0.0-alpha.58`: - -0. (recommended) Make a backup of your files and database. - -1. Download the latest release, overwrite your files whilst keeping `.env` and - `public/media`. - -2. Go through each release update instructions sequentially (from oldest to - newest) starting with `v1.0.0-alpha.43`, `v1.0.0-alpha.44`, - `v1.0.0-alpha.45`, …, `v1.0.0-alpha.58`. - -3. ✨ Enjoy your fresh instance, you're all done! - -### Should I make a backup before updating? - -We advise you do, so you don't lose everything if anything goes wrong! - -More generally, we advise you make regular backups of your Castopod Host files -and database to prevent you from losing it all… diff --git a/app/.htaccess b/app/.htaccess index f24db0ac..e64d9494 100644 --- a/app/.htaccess +++ b/app/.htaccess @@ -1,6 +1,2 @@ - - Require all denied - - - Deny from all - + Require all denied + Deny from all diff --git a/app/Authorization/FlatAuthorization.php b/app/Authorization/FlatAuthorization.php deleted file mode 100644 index 31d90630..00000000 --- a/app/Authorization/FlatAuthorization.php +++ /dev/null @@ -1,54 +0,0 @@ -getPermissionID($permission); - - if (! is_numeric($permissionId)) { - return false; - } - - return $this->permissionModel->doesGroupHavePermission($groupId, $permissionId); - } - - /** - * Makes user part of given groups. - * - * @param array $groups Either collection of ID or names - */ - public function setUserGroups(int $userId, array $groups = []): bool - { - // remove user from all groups before resetting it in new groups - $this->groupModel->removeUserFromAllGroups($userId); - - if ($groups === []) { - return true; - } - - foreach ($groups as $group) { - $this->addUserToGroup($userId, $group); - } - - return true; - } -} diff --git a/app/Authorization/GroupModel.php b/app/Authorization/GroupModel.php deleted file mode 100644 index 1e2e74a3..00000000 --- a/app/Authorization/GroupModel.php +++ /dev/null @@ -1,30 +0,0 @@ -select('auth_groups.*') - ->like('name', 'podcast_', 'after') - ->findAll(); - } - - /** - * @return mixed[] - */ - public function getUserRoles(): array - { - return $this->select('auth_groups.*') - ->notLike('name', 'podcast_', 'after') - ->findAll(); - } -} diff --git a/app/Authorization/PermissionModel.php b/app/Authorization/PermissionModel.php deleted file mode 100644 index 72329220..00000000 --- a/app/Authorization/PermissionModel.php +++ /dev/null @@ -1,53 +0,0 @@ -getPermissionsForGroup($groupId); - - return count($groupPerms) && - array_key_exists($permissionId, $groupPerms); - } - - /** - * Gets all permissions for a group in a way that can be easily used to check against: - * - * [ id => name, id => name ] - * - * @return array - */ - public function getPermissionsForGroup(int $groupId): array - { - $cacheName = "group{$groupId}_permissions"; - if (! ($found = cache($cacheName))) { - $groupPermissions = $this->db - ->table('auth_groups_permissions') - ->select('id, auth_permissions.name') - ->join('auth_permissions', 'auth_permissions.id = permission_id', 'inner') - ->where('group_id', $groupId) - ->get() - ->getResultObject(); - - $found = []; - foreach ($groupPermissions as $row) { - $found[$row->id] = strtolower($row->name); - } - - cache() - ->save($cacheName, $found, 300); - } - - return $found; - } -} diff --git a/app/Commands/EpisodesComputeDownloads.php b/app/Commands/EpisodesComputeDownloads.php new file mode 100644 index 00000000..1bdc7b2d --- /dev/null +++ b/app/Commands/EpisodesComputeDownloads.php @@ -0,0 +1,50 @@ +builder() + ->select('episodes.id as id, IFNULL(SUM(ape.hits),0) as downloads_count') + ->join('analytics_podcasts_by_episode ape', 'episodes.id=ape.episode_id', 'left') + ->groupBy('episodes.id'); + + $episodeModel2 = new EpisodeModel(); + $episodeModel2->builder() + ->setQueryAsData($query) + ->onConstraint('id') + ->updateBatch(); + } +} diff --git a/app/Common.php b/app/Common.php index 7448f1ad..89981c0d 100644 --- a/app/Common.php +++ b/app/Common.php @@ -2,13 +2,49 @@ declare(strict_types=1); +use ViewThemes\Theme; + /** * The goal of this file is to allow developers a location where they can overwrite core procedural functions and - * replace them with their own. This file is loaded during the bootstrap process and is called during the frameworks + * replace them with their own. This file is loaded during the bootstrap process and is called during the framework's * execution. * * This can be looked at as a `master helper` file that is loaded early on, and may also contain additional functions * that you'd like to use throughout your entire application * - * @link: https://codeigniter4.github.io/CodeIgniter4/ + * @see: https://codeigniter.com/user_guide/extending/common.html */ + +if (! function_exists('view')) { + /** + * Grabs the current RendererInterface-compatible class and tells it to render the specified view. Simply provides a + * convenience method that can be used in Controllers, libraries, and routed closures. + * + * NOTE: Does not provide any escaping of the data, so that must all be handled manually by the developer. + * + * @param array $data + * @param array $options Unused - reserved for third-party extensions. + */ + function view(string $name, array $data = [], array $options = []): string + { + if (array_key_exists('theme', $options)) { + Theme::setTheme($options['theme']); + } + + $path = Theme::path(); + + /** @var CodeIgniter\View\View $renderer */ + $renderer = single_service('renderer', $path); + + $saveData = config('View') + ->saveData; + + if (array_key_exists('saveData', $options)) { + $saveData = (bool) $options['saveData']; + unset($options['saveData']); + } + + return $renderer->setData($data, 'raw') + ->render($name, $options, $saveData); + } +} diff --git a/app/Config/ActivityPub.php b/app/Config/ActivityPub.php deleted file mode 100644 index 45e1f1a5..00000000 --- a/app/Config/ActivityPub.php +++ /dev/null @@ -1,31 +0,0 @@ - 'permission:podcasts-view,podcast-view', - 'analytics-data' => 'permission:podcasts-view,podcast-view', - 'analytics-filtered-data' => 'permission:podcasts-view,podcast-view', - ]; - - public function __construct() - { - parent::__construct(); - - // set the analytics gateway behind the admin gateway. - // Only logged in users should be able to view analytics - $this->gateway = config('App') - ->adminGateway . '/analytics'; - } - - /** - * get the full audio file url - * - * @param string|string[] $audioFilePath - */ - public function getAudioFileUrl($audioFilePath): string - { - helper('media'); - - return media_base_url($audioFilePath); - } -} diff --git a/app/Config/App.php b/app/Config/App.php index 4eb43e32..404ff5a0 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Config; use CodeIgniter\Config\BaseConfig; -use CodeIgniter\Session\Handlers\FileHandler; +use Override; class App extends BaseConfig { @@ -14,38 +14,34 @@ class App extends BaseConfig * Base Site URL * -------------------------------------------------------------------------- * - * URL to your CodeIgniter root. Typically this will be your base URL, + * URL to your CodeIgniter root. Typically, this will be your base URL, * WITH a trailing slash: * - * http://example.com/ - * - * If this is not set then CodeIgniter will try guess the protocol, domain - * and path to your installation. However, you should always configure this - * explicitly and never rely on auto-guessing, especially in production - * environments. + * E.g., http://example.com/ */ public string $baseURL = 'http://localhost:8080/'; /** - * -------------------------------------------------------------------------- - * Media Base URL - * -------------------------------------------------------------------------- + * Allowed Hostnames in the Site URL other than the hostname in the baseURL. + * If you want to accept multiple Hostnames, set this. * - * URL to your media root. Typically this will be your base URL, - * WITH a trailing slash: + * E.g., + * When your site URL ($baseURL) is 'http://example.com/', and your site + * also accepts 'http://media.example.com/' and 'http://accounts.example.com/': + * ['media.example.com', 'accounts.example.com'] * - * http://cdn.example.com/ + * @var list */ - public string $mediaBaseURL = 'http://localhost:8080/'; + public array $allowedHostnames = []; /** * -------------------------------------------------------------------------- * Index File * -------------------------------------------------------------------------- * - * Typically this will be your index.php file, unless you've renamed it to - * something else. If you are using mod_rewrite to remove the page set this - * variable so that it is blank. + * Typically, this will be your `index.php` file, unless you've renamed it to + * something else. If you have configured your web server to remove this file + * from your site URIs, set this variable to an empty string. */ public string $indexPage = ''; @@ -54,18 +50,42 @@ class App extends BaseConfig * URI PROTOCOL * -------------------------------------------------------------------------- * - * This item determines which getServer global should be used to retrieve the - * URI string. The default setting of 'REQUEST_URI' works for most servers. + * This item determines which server global should be used to retrieve the + * URI string. The default setting of 'REQUEST_URI' works for most servers. * If your links do not seem to work, try one of the other delicious flavors: * - * 'REQUEST_URI' Uses $_SERVER['REQUEST_URI'] - * 'QUERY_STRING' Uses $_SERVER['QUERY_STRING'] - * 'PATH_INFO' Uses $_SERVER['PATH_INFO'] + * 'REQUEST_URI': Uses $_SERVER['REQUEST_URI'] + * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING'] + * 'PATH_INFO': Uses $_SERVER['PATH_INFO'] * * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded! */ public string $uriProtocol = 'REQUEST_URI'; + /* + *-------------------------------------------------------------------------- + * Allowed URL Characters + *-------------------------------------------------------------------------- + * + * This lets you specify which characters are permitted within your URLs. + * When someone tries to submit a URL with disallowed characters they will + * get a warning message. + * + * As a security measure you are STRONGLY encouraged to restrict URLs to + * as few characters as possible. + * + * By default, only these are allowed: `a-z 0-9~%.:_-` + * + * Set an empty string to allow all characters -- but only if you are insane. + * + * The configured value is actually a regular expression character group + * and it will be used as: '/\A[]+\z/iu' + * + * DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! + * + */ + public string $permittedURIChars = 'a-z 0-9~%.:_\-@'; + /** * -------------------------------------------------------------------------- * Default Locale @@ -99,9 +119,23 @@ class App extends BaseConfig * by the application in descending order of priority. If no match is * found, the first locale will be used. * - * @var string[] + * IncomingRequest::setLocale() also uses this list. + * + * @var list */ - public array $supportedLocales = ['en', 'fr']; + public array $supportedLocales = [ + 'en', + 'fr', + 'pl', + 'de', + 'pt-br', + 'nn-no', + 'es', + 'zh-hans', + 'ca', + 'br', + 'sr-latn', + ]; /** * -------------------------------------------------------------------------- @@ -110,6 +144,9 @@ class App extends BaseConfig * * The default timezone that will be used in your application to display * dates with the date helper, and can be retrieved through app_timezone() + * + * @see https://www.php.net/manual/en/timezones.php for list of timezones + * supported by PHP. */ public string $appTimezone = 'UTC'; @@ -133,170 +170,10 @@ class App extends BaseConfig * If true, this will force every request made to this application to be * made via a secure connection (HTTPS). If the incoming request is not * secure, the user will be redirected to a secure version of the page - * and the HTTP Strict Transport Security header will be set. + * and the HTTP Strict Transport Security (HSTS) header will be set. */ public bool $forceGlobalSecureRequests = true; - /** - * -------------------------------------------------------------------------- - * Session Driver - * -------------------------------------------------------------------------- - * - * The session storage driver to use: - * - `CodeIgniter\Session\Handlers\FileHandler` - * - `CodeIgniter\Session\Handlers\DatabaseHandler` - * - `CodeIgniter\Session\Handlers\MemcachedHandler` - * - `CodeIgniter\Session\Handlers\RedisHandler` - */ - public string $sessionDriver = FileHandler::class; - - /** - * -------------------------------------------------------------------------- - * Session Cookie Name - * -------------------------------------------------------------------------- - * - * The session cookie name, must contain only [0-9a-z_-] characters - */ - public string $sessionCookieName = 'ci_session'; - - /** - * -------------------------------------------------------------------------- - * Session Expiration - * -------------------------------------------------------------------------- - * - * The number of SECONDS you want the session to last. - * Setting to 0 (zero) means expire when the browser is closed. - */ - public int $sessionExpiration = 7200; - - /** - * -------------------------------------------------------------------------- - * Session Save Path - * -------------------------------------------------------------------------- - * - * The location to save sessions to and is driver dependent. - * - * For the 'files' driver, it's a path to a writable directory. - * WARNING: Only absolute paths are supported! - * - * For the 'database' driver, it's a table name. - * Please read up the manual for the format with other session drivers. - * - * IMPORTANT: You are REQUIRED to set a valid save path! - */ - public string $sessionSavePath = WRITEPATH . 'session'; - - /** - * -------------------------------------------------------------------------- - * Session Match IP - * -------------------------------------------------------------------------- - * - * Whether to match the user's IP address when reading the session data. - * - * WARNING: If you're using the database driver, don't forget to update - * your session table's PRIMARY KEY when changing this setting. - */ - public bool $sessionMatchIP = false; - - /** - * -------------------------------------------------------------------------- - * Session Time to Update - * -------------------------------------------------------------------------- - * - * How many seconds between CI regenerating the session ID. - */ - public int $sessionTimeToUpdate = 300; - - /** - * -------------------------------------------------------------------------- - * Session Regenerate Destroy - * -------------------------------------------------------------------------- - * - * Whether to destroy session data associated with the old session ID - * when auto-regenerating the session ID. When set to FALSE, the data - * will be later deleted by the garbage collector. - */ - public bool $sessionRegenerateDestroy = false; - - /** - * -------------------------------------------------------------------------- - * Cookie Prefix - * -------------------------------------------------------------------------- - * - * Set a cookie name prefix if you need to avoid collisions. - * - * @deprecated use Config\Cookie::$prefix property instead. - */ - public string $cookiePrefix = ''; - - /** - * -------------------------------------------------------------------------- - * Cookie Domain - * -------------------------------------------------------------------------- - * - * Set to `.your-domain.com` for site-wide cookies. - * - * @deprecated use Config\Cookie::$domain property instead. - */ - public string $cookieDomain = ''; - - /** - * -------------------------------------------------------------------------- - * Cookie Path - * -------------------------------------------------------------------------- - * - * Typically will be a forward slash. - * - * @deprecated use Config\Cookie::$path property instead. - */ - public string $cookiePath = '/'; - - /** - * -------------------------------------------------------------------------- - * Cookie Secure - * -------------------------------------------------------------------------- - * - * Cookie will only be set if a secure HTTPS connection exists. - * - * @deprecated use Config\Cookie::$secure property instead. - */ - public bool $cookieSecure = false; - - /** - * -------------------------------------------------------------------------- - * Cookie HttpOnly - * -------------------------------------------------------------------------- - * - * Cookie will only be accessible via HTTP(S) (no JavaScript). - * - * @deprecated use Config\Cookie::$httponly property instead. - */ - public bool $cookieHTTPOnly = true; - - /** - * -------------------------------------------------------------------------- - * Cookie SameSite - * -------------------------------------------------------------------------- - * - * Configure cookie SameSite setting. Allowed values are: - * - None - * - Lax - * - Strict - * - '' - * - * Alternatively, you can use the constant names: - * - `Cookie::SAMESITE_NONE` - * - `Cookie::SAMESITE_LAX` - * - `Cookie::SAMESITE_STRICT` - * - * Defaults to `Lax` for compatibility with modern browsers. Setting `''` - * (empty string) means default SameSite attribute set by browsers (`Lax`) - * will be set on cookies. If set to `None`, `$cookieSecure` must also be set. - * - * @deprecated use Config\Cookie::$samesite property instead. - */ - public string $cookieSameSite = 'Lax'; - /** * -------------------------------------------------------------------------- * Reverse Proxy IPs @@ -304,103 +181,21 @@ class App extends BaseConfig * * If your server is behind a reverse proxy, you must whitelist the proxy * IP addresses from which CodeIgniter should trust headers such as - * HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify + * X-Forwarded-For or Client-IP in order to properly identify * the visitor's IP address. * - * You can use both an array or a comma-separated list of proxy addresses, - * as well as specifying whole subnets. Here are a few examples: + * You need to set a proxy IP address or IP address with subnets and + * the HTTP header for the client IP address. * - * Comma-separated: '10.0.1.200,192.168.5.0/24' - * Array: ['10.0.1.200', '192.168.5.0/24'] + * Here are some examples: + * [ + * '10.0.1.200' => 'X-Forwarded-For', + * '192.168.5.0/24' => 'X-Real-IP', + * ] * - * @var string|string[] + * @var array|string */ - public string | array $proxyIPs = ''; - - /** - * -------------------------------------------------------------------------- - * CSRF Token Name - * -------------------------------------------------------------------------- - * - * The token name. - * - * @deprecated Use `Config\Security` $tokenName property instead of using this property. - */ - public string $CSRFTokenName = 'csrf_test_name'; - - /** - * -------------------------------------------------------------------------- - * CSRF Header Name - * -------------------------------------------------------------------------- - * - * The header name. - * - * @deprecated Use `Config\Security` $headerName property instead of using this property. - */ - public string $CSRFHeaderName = 'X-CSRF-TOKEN'; - - /** - * -------------------------------------------------------------------------- - * CSRF Cookie Name - * -------------------------------------------------------------------------- - * - * The cookie name. - * - * @deprecated Use `Config\Security` $cookieName property instead of using this property. - */ - public string $CSRFCookieName = 'csrf_cookie_name'; - - /** - * -------------------------------------------------------------------------- - * CSRF Expire - * -------------------------------------------------------------------------- - * - * The number in seconds the token should expire. - * - * @deprecated Use `Config\Security` $expire property instead of using this property. - */ - public int $CSRFExpire = 7200; - - /** - * -------------------------------------------------------------------------- - * CSRF Regenerate - * -------------------------------------------------------------------------- - * - * Regenerate token on every submission? - * - * @deprecated Use `Config\Security` $regenerate property instead of using this property. - */ - public bool $CSRFRegenerate = true; - - /** - * -------------------------------------------------------------------------- - * CSRF Redirect - * -------------------------------------------------------------------------- - * - * Redirect to previous page with error on failure? - * - * @deprecated Use `Config\Security` $redirect property instead of using this property. - */ - public bool $CSRFRedirect = true; - - /** - * -------------------------------------------------------------------------- - * CSRF SameSite - * -------------------------------------------------------------------------- - * - * Setting for CSRF SameSite cookie token. Allowed values are: - * - None - * - Lax - * - Strict - * - '' - * - * Defaults to `Lax` as recommended in this link: - * - * @see https://portswigger.net/web-security/csrf/samesite-cookies - * - * @deprecated Use `Config\Security` $samesite property instead of using this property. - */ - public string $CSRFSameSite = 'Lax'; + public $proxyIPs = []; /** * -------------------------------------------------------------------------- @@ -422,33 +217,70 @@ class App extends BaseConfig /** * -------------------------------------------------------------------------- - * Media root folder + * Instance / Site Config * -------------------------------------------------------------------------- - * Defines the root folder for media files storage */ - public string $mediaRoot = 'media'; + public string $siteName = 'Castopod'; + + public string $siteTitleSeparator = ' | '; + + public string $siteDescription = 'Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.'; /** - * -------------------------------------------------------------------------- - * Admin gateway - * -------------------------------------------------------------------------- - * Defines a base route for all admin pages + * @var array */ - public string $adminGateway = 'cp-admin'; + public array $siteIcon = [ + 'ico' => '/favicon.ico', + '64' => '/icon-64.png', + '180' => '/icon-180.png', + '192' => '/icon-192.png', + '512' => '/icon-512.png', + ]; + + public string $theme = 'pine'; /** - * -------------------------------------------------------------------------- - * Auth gateway - * -------------------------------------------------------------------------- - * Defines a base route for all authentication related pages + * Storage limit in Gigabytes */ - public string $authGateway = 'cp-auth'; + public ?int $storageLimit = null; /** - * -------------------------------------------------------------------------- - * Install gateway - * -------------------------------------------------------------------------- - * Defines a base route for instance installation + * Bandwidth limit (per month) in Gigabytes */ - public string $installGateway = 'cp-install'; + public ?int $bandwidthLimit = null; + + public ?string $legalNoticeURL = null; + + /** + * AuthToken Config Constructor + */ + public function __construct() + { + parent::__construct(); + + if (is_string($this->proxyIPs)) { + $array = json_decode($this->proxyIPs, true); + if (is_array($array)) { + $this->proxyIPs = $array; + } + } + } + + /** + * Override parent initEnvValue() to allow for direct setting to array properties values from ENV + * + * In order to set array properties via ENV vars we need to set the property to a string value first. + * + * @param mixed $property + */ + #[Override] + protected function initEnvValue(&$property, string $name, string $prefix, string $shortPrefix): void + { + // if attempting to set property from ENV, first set to empty string + if ($name === 'proxyIPs' && $this->getEnvValue($name, $prefix, $shortPrefix) !== null) { + $property = ''; + } + + parent::initEnvValue($property, $name, $prefix, $shortPrefix); + } } diff --git a/app/Config/Auth.php b/app/Config/Auth.php deleted file mode 100644 index 08e2e624..00000000 --- a/app/Config/Auth.php +++ /dev/null @@ -1,58 +0,0 @@ - - */ - public $views = [ - 'login' => 'auth/login', - 'register' => 'auth/register', - 'forgot' => 'auth/forgot', - 'reset' => 'auth/reset', - 'emailForgot' => 'auth/emails/forgot', - 'emailActivation' => 'auth/emails/activation', - ]; - - /** - * -------------------------------------------------------------------------- - * Layout for the views to extend - * -------------------------------------------------------------------------- - * - * @var string - */ - public $viewLayout = 'auth/_layout'; - - /** - * -------------------------------------------------------------------------- - * Allow User Registration - * -------------------------------------------------------------------------- - * When enabled (default) any unregistered user may apply for a new - * account. If you disable registration you may need to ensure your - * controllers and views know not to offer registration. - * - * @var bool - */ - public $allowRegistration = false; - - /** - * -------------------------------------------------------------------------- - * Require confirmation registration via email - * -------------------------------------------------------------------------- - * When enabled, every registered user will receive an email message - * with a special link he have to confirm to activate his account. - * - * @var bool - */ - public $requireActivation = false; -} diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php index 1bc7dd61..3fd8e175 100644 --- a/app/Config/Autoload.php +++ b/app/Config/Autoload.php @@ -27,30 +27,39 @@ class Autoload extends AutoloadConfig * their location on the file system. These are used by the autoloader * to locate files the first time they have been instantiated. * - * The '/app' and '/system' directories are already mapped for you. - * you may change the name of the 'App' namespace if you wish, + * The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are + * already mapped for you. + * + * You may change the name of the 'App' namespace if you wish, * but this should be done prior to creating any namespaced classes, * else you will need to modify all of those classes for this to work. * - * Prototype: - * - * $psr4 = [ - * 'CodeIgniter' => SYSTEMPATH, - * 'App' => APPPATH - * ]; - * - * @var array + * @var array|string> */ public $psr4 = [ - APP_NAMESPACE => APPPATH, - 'Config' => APPPATH . 'Config', - 'ActivityPub' => APPPATH . 'Libraries/ActivityPub', - 'Analytics' => APPPATH . 'Libraries/Analytics', + APP_NAMESPACE => APPPATH, + 'Modules' => ROOTPATH . 'modules/', + 'Modules\Admin' => ROOTPATH . 'modules/Admin/', + 'Modules\Analytics' => ROOTPATH . 'modules/Analytics/', + 'Modules\Api\Rest\V1' => ROOTPATH . 'modules/Api/Rest/V1', + 'Modules\Auth' => ROOTPATH . 'modules/Auth/', + 'Modules\Fediverse' => ROOTPATH . 'modules/Fediverse/', + 'Modules\Install' => ROOTPATH . 'modules/Install/', + 'Modules\Media' => ROOTPATH . 'modules/Media/', + 'Modules\MediaClipper' => ROOTPATH . 'modules/MediaClipper/', + 'Modules\Platforms' => ROOTPATH . 'modules/Platforms/', + 'Modules\Plugins' => ROOTPATH . 'modules/Plugins/', + 'Modules\PodcastImport' => ROOTPATH . 'modules/PodcastImport/', + 'Modules\PremiumPodcasts' => ROOTPATH . 'modules/PremiumPodcasts/', + 'Modules\Update' => ROOTPATH . 'modules/Update/', + 'Modules\WebSub' => ROOTPATH . 'modules/WebSub/', + 'Themes' => ROOTPATH . 'themes', + 'ViewComponents' => APPPATH . 'Libraries/ViewComponents/', + 'ViewThemes' => APPPATH . 'Libraries/ViewThemes/', ]; /** * ------------------------------------------------------------------- - * Class Map * ------------------------------------------------------------------- * The class map provides a map of class names and their exact * location on the drive. Classes loaded in this manner will have @@ -77,12 +86,25 @@ class Autoload extends AutoloadConfig * or for loading functions. * * Prototype: - * ``` + * * $files = [ * '/path/to/my/file.php', * ]; - * ``` - * @var array + * + * @var list */ public $files = []; + + /** + * ------------------------------------------------------------------- + * Helpers + * ------------------------------------------------------------------- + * Prototype: + * $helpers = [ + * 'form', + * ]; + * + * @var list + */ + public $helpers = ['auth', 'setting', 'plugins']; } diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php index 8193a56a..e131d316 100644 --- a/app/Config/Boot/development.php +++ b/app/Config/Boot/development.php @@ -9,8 +9,10 @@ declare(strict_types=1); * In development, we want to show as many errors as possible to help * make sure they don't make it to production. And save us hours of * painful debugging. + * + * If you set 'display_errors' to '1', CI4's detailed error report will show. */ -error_reporting(-1); +error_reporting(E_ALL); ini_set('display_errors', '1'); /** diff --git a/app/Config/Boot/production.php b/app/Config/Boot/production.php index 4cf210d8..9d22b60a 100644 --- a/app/Config/Boot/production.php +++ b/app/Config/Boot/production.php @@ -8,9 +8,13 @@ declare(strict_types=1); * -------------------------------------------------------------------------- * Don't show ANY in production environments. Instead, let the system catch * it and display a generic error message. + * + * If you set 'display_errors' to '1', CI4's detailed error report will show. */ +error_reporting(E_ALL & ~E_DEPRECATED); +// If you want to suppress more types of errors. +// error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED); ini_set('display_errors', '0'); -error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED); /** * -------------------------------------------------------------------------- diff --git a/app/Config/Boot/testing.php b/app/Config/Boot/testing.php index 56c22a9c..46e757da 100644 --- a/app/Config/Boot/testing.php +++ b/app/Config/Boot/testing.php @@ -2,6 +2,12 @@ declare(strict_types=1); +/* + * The environment testing is reserved for PHPUnit testing. It has special + * conditions built into the framework at various places to assist with that. + * You can’t use it for your development. + */ + /** * -------------------------------------------------------------------------- * ERROR DISPLAY @@ -10,7 +16,7 @@ declare(strict_types=1); * make sure they don't make it to production. And save us hours of * painful debugging. */ -error_reporting(-1); +error_reporting(E_ALL); ini_set('display_errors', '1'); /** diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php new file mode 100644 index 00000000..4dbb7afa --- /dev/null +++ b/app/Config/CURLRequest.php @@ -0,0 +1,35 @@ + + * + * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect + */ + public array $shareConnectionOptions = [CURL_LOCK_DATA_CONNECT, CURL_LOCK_DATA_DNS]; + + /** + * -------------------------------------------------------------------------- + * CURLRequest Share Options + * -------------------------------------------------------------------------- + * + * Whether share options between requests or not. + * + * If true, all the options won't be reset between requests. + * It may cause an error request with unnecessary headers. + */ + public bool $shareOptions = false; +} diff --git a/app/Config/Cache.php b/app/Config/Cache.php index f08efbc6..bbf812f9 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Config; +use CodeIgniter\Cache\CacheInterface; +use CodeIgniter\Cache\Handlers\ApcuHandler; use CodeIgniter\Cache\Handlers\DummyHandler; use CodeIgniter\Cache\Handlers\FileHandler; use CodeIgniter\Cache\Handlers\MemcachedHandler; @@ -35,37 +37,6 @@ class Cache extends BaseConfig */ public string $backupHandler = 'dummy'; - /** - * -------------------------------------------------------------------------- - * Cache Directory Path - * -------------------------------------------------------------------------- - * - * The path to where cache files should be stored, if using a file-based - * system. - * - * @deprecated Use the driver-specific variant under $file - */ - public string $storePath = WRITEPATH . 'cache/'; - - /** - * -------------------------------------------------------------------------- - * Cache Include Query String - * -------------------------------------------------------------------------- - * - * Whether to take the URL query string into consideration when generating - * output cache files. Valid options are: - * - * false = Disabled - * true = Enabled, take all query parameters into account. - * Please be aware that this may result in numerous cache - * files generated for the same page over and over again. - * array('q') = Enabled, but only take into account the specified list - * of query parameters. - * - * @var boolean|string[] - */ - public bool | array $cacheQueryString = false; - /** * -------------------------------------------------------------------------- * Key Prefix @@ -89,36 +60,51 @@ class Cache extends BaseConfig */ public int $ttl = 60; + /** + * -------------------------------------------------------------------------- + * Reserved Characters + * -------------------------------------------------------------------------- + * + * A string of reserved characters that will not be allowed in keys or tags. + * Strings that violate this restriction will cause handlers to throw. + * Default: {}()/\@: + * + * Note: The default set is required for PSR-6 compliance. + */ + public string $reservedCharacters = '{}()/\@:'; + /** * -------------------------------------------------------------------------- * File settings * -------------------------------------------------------------------------- + * * Your file storage preferences can be specified below, if you are using * the File driver. * - * @var array + * @var array{storePath?: string, mode?: int} */ public array $file = [ 'storePath' => WRITEPATH . 'cache/', - 'mode' => 0640, + 'mode' => 0640, ]; /** * ------------------------------------------------------------------------- * Memcached settings * ------------------------------------------------------------------------- + * * Your Memcached servers can be specified below, if you are using * the Memcached drivers. * * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached * - * @var array + * @var array{host?: string, port?: int, weight?: int, raw?: bool} */ public array $memcached = [ - 'host' => '127.0.0.1', - 'port' => 11211, + 'host' => '127.0.0.1', + 'port' => 11211, 'weight' => 1, - 'raw' => false, + 'raw' => false, ]; /** @@ -128,14 +114,24 @@ class Cache extends BaseConfig * Your Redis server can be specified below, if you are using * the Redis or Predis drivers. * - * @var array + * @var array{ + * host?: string, + * password?: string|null, + * port?: int, + * timeout?: int, + * async?: bool, + * persistent?: bool, + * database?: int + * } */ public array $redis = [ - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'async' => false, // specific to Predis and ignored by the native Redis extension + 'persistent' => false, + 'database' => 0, ]; /** @@ -146,14 +142,58 @@ class Cache extends BaseConfig * This is an array of cache engine alias' and class names. Only engines * that are listed here are allowed to be used. * - * @var array + * @var array> */ public array $validHandlers = [ - 'dummy' => DummyHandler::class, - 'file' => FileHandler::class, + 'apcu' => ApcuHandler::class, + 'dummy' => DummyHandler::class, + 'file' => FileHandler::class, 'memcached' => MemcachedHandler::class, - 'predis' => PredisHandler::class, - 'redis' => RedisHandler::class, - 'wincache' => WincacheHandler::class, + 'predis' => PredisHandler::class, + 'redis' => RedisHandler::class, + 'wincache' => WincacheHandler::class, ]; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Include Query String + * -------------------------------------------------------------------------- + * + * Whether to take the URL query string into consideration when generating + * output cache files. Valid options are: + * + * false = Disabled + * true = Enabled, take all query parameters into account. + * Please be aware that this may result in numerous cache + * files generated for the same page over and over again. + * ['q'] = Enabled, but only take into account the specified list + * of query parameters. + * + * @var bool|list + */ + public $cacheQueryString = false; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Status Codes + * -------------------------------------------------------------------------- + * + * HTTP status codes that are allowed to be cached. Only responses with + * these status codes will be cached by the PageCache filter. + * + * Default: [] - Cache all status codes (backward compatible) + * + * Recommended: [200] - Only cache successful responses + * + * You can also use status codes like: + * [200, 404, 410] - Cache successful responses and specific error codes + * [200, 201, 202, 203, 204] - All 2xx successful responses + * + * WARNING: Using [] may cache temporary error pages (404, 500, etc). + * Consider restricting to [200] for production applications to avoid + * caching errors that should be temporary. + * + * @var list + */ + public array $cacheStatusCodes = []; } diff --git a/app/Config/Colors.php b/app/Config/Colors.php new file mode 100644 index 00000000..49618892 --- /dev/null +++ b/app/Config/Colors.php @@ -0,0 +1,150 @@ +> + */ + public array $themes = [ + /* Castopod's brand color */ + 'pine' => [ + 'accent-base' => [174, 100, 29], + 'accent-hover' => [172, 100, 17], + 'accent-muted' => [131, 100, 12], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [172, 100, 17], + 'heading-background' => [111, 64, 94], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [173, 44, 96], + 'background-navigation' => [172, 100, 17], + 'background-header' => [172, 100, 17], + 'background-highlight' => [111, 64, 94], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [111, 42, 86], + 'border-contrast' => [0, 0, 0], + 'border-navigation' => [131, 100, 12], + + 'text-base' => [158, 8, 3], + 'text-muted' => [172, 8, 38], + ], + /* Red / Rose color */ + 'crimson' => [ + 'accent-base' => [350, 87, 61], + 'accent-hover' => [348, 75, 40], + 'accent-muted' => [348, 73, 32], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [348, 73, 32], + 'heading-background' => [344, 79, 96], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [350, 44, 96], + 'background-header' => [348, 75, 40], + 'background-highlight' => [344, 79, 96], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [348, 42, 86], + 'border-contrast' => [0, 0, 0], + + 'text-base' => [340, 8, 3], + 'text-muted' => [345, 8, 38], + ], + /* Blue color */ + 'lake' => [ + 'accent-base' => [194, 100, 44], + 'accent-hover' => [194, 100, 22], + 'accent-muted' => [195, 100, 11], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [194, 100, 22], + 'heading-background' => [195, 100, 92], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [196, 44, 96], + 'background-header' => [194, 100, 22], + 'background-highlight' => [195, 100, 92], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [195, 42, 86], + 'border-contrast' => [0, 0, 0], + + 'text-base' => [194, 8, 3], + 'text-muted' => [195, 8, 38], + ], + /* Orange color */ + 'amber' => [ + 'accent-base' => [17, 100, 57], + 'accent-hover' => [17, 100, 35], + 'accent-muted' => [17, 100, 24], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [17, 100, 35], + 'heading-background' => [17, 100, 89], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [15, 44, 96], + 'background-header' => [17, 100, 35], + 'background-highlight' => [17, 100, 89], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [17, 42, 86], + 'border-contrast' => [0, 0, 0], + + 'text-base' => [15, 8, 3], + 'text-muted' => [17, 8, 38], + ], + /* Violet color */ + 'jacaranda' => [ + 'accent-base' => [254, 72, 52], + 'accent-hover' => [254, 73, 30], + 'accent-muted' => [254, 71, 19], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [254, 73, 30], + 'heading-background' => [254, 73, 84], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [253, 44, 96], + 'background-header' => [254, 73, 30], + 'background-highlight' => [254, 88, 91], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [254, 42, 86], + 'border-contrast' => [0, 0, 0], + + 'text-base' => [253, 8, 3], + 'text-muted' => [254, 8, 38], + ], + /* Black color */ + 'onyx' => [ + 'accent-base' => [240, 17, 2], + 'accent-hover' => [240, 17, 17], + 'accent-muted' => [240, 17, 17], + 'accent-contrast' => [0, 0, 100], + + 'heading-foreground' => [240, 17, 17], + 'heading-background' => [240, 17, 94], + + 'background-elevated' => [0, 0, 100], + 'background-base' => [240, 17, 96], + 'background-header' => [240, 12, 17], + 'background-highlight' => [240, 17, 94], + 'background-backdrop' => [0, 0, 50], + + 'border-subtle' => [240, 17, 86], + 'border-contrast' => [0, 0, 0], + + 'text-base' => [240, 8, 3], + 'text-muted' => [240, 8, 38], + ], + ]; +} diff --git a/app/Config/Constants.php b/app/Config/Constants.php index 365709ac..e23c0e0d 100644 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -11,7 +11,7 @@ declare(strict_types=1); | | NOTE: this constant is updated upon release with Continuous Integration. */ -defined('CP_VERSION') || define('CP_VERSION', '1.0.0-alpha.80'); +defined('CP_VERSION') || define('CP_VERSION', '2.0.0-next.3'); /* | -------------------------------------------------------------------- @@ -24,10 +24,23 @@ defined('CP_VERSION') || define('CP_VERSION', '1.0.0-alpha.80'); | classes should use. | | NOTE: changing this will require manually modifying the - | existing namespaces of App\* namespaced-classes. + | existing namespaces of App* namespaced-classes. */ defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App'); +/* + | -------------------------------------------------------------------- + | Plugins Path + | -------------------------------------------------------------------- + | + | This defines the folder in which plugins will live. + */ +defined('PLUGINS_PATH') || + define('PLUGINS_PATH', ROOTPATH . 'plugins' . DIRECTORY_SEPARATOR); + +defined('PLUGINS_KEY_PATTERN') || + define('PLUGINS_KEY_PATTERN', '[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*'); + /* | -------------------------------------------------------------------------- | Composer Path @@ -52,9 +65,9 @@ defined('MINUTE') || define('MINUTE', 60); defined('HOUR') || define('HOUR', 3600); defined('DAY') || define('DAY', 86400); defined('WEEK') || define('WEEK', 604800); -defined('MONTH') || define('MONTH', 2592000); -defined('YEAR') || define('YEAR', 31536000); -defined('DECADE') || define('DECADE', 315360000); +defined('MONTH') || define('MONTH', 2_592_000); +defined('YEAR') || define('YEAR', 31_536_000); +defined('DECADE') || define('DECADE', 315_360_000); /* | -------------------------------------------------------------------------- diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php index 44670867..99fa0b0a 100644 --- a/app/Config/ContentSecurityPolicy.php +++ b/app/Config/ContentSecurityPolicy.php @@ -26,37 +26,77 @@ class ContentSecurityPolicy extends BaseConfig */ public ?string $reportURI = null; + /** + * Specifies a reporting endpoint to which violation reports ought to be sent. + */ + public ?string $reportTo = null; + /** * Instructs user agents to rewrite URL schemes, changing HTTP to HTTPS. This directive is for websites with large * numbers of old URLs that need to be rewritten. */ public bool $upgradeInsecureRequests = false; + // ------------------------------------------------------------------------- + // CSP DIRECTIVES SETTINGS + // NOTE: once you set a policy to 'none', it cannot be further restricted + // ------------------------------------------------------------------------- + /** - * Will default to self if not overridden + * Will default to `'self'` if not overridden * - * @var string|string[]|null + * @var list|string|null */ public string | array | null $defaultSrc = null; /** * Lists allowed scripts' URLs. * - * @var string|string[] + * @var list|string */ public string | array $scriptSrc = 'self'; + /** + * Specifies valid sources for JavaScript + HTML); + + if ($this->title) { + $this->tag('title', esc($this->title)); + } + + if (url_is(route_to('admin') . '*') || url_is(base_url(config('Auth')->gateway) . '*')) { + // restricted admin and auth areas, do not index + $this->meta('robots', 'noindex'); + } else { + // public website, set siteHead hook only there + service('plugins') + ->siteHead($this); + } + + $head = ''; + foreach ($this->tags as $tag) { + if ($tag['value'] === null) { + $head .= <<stringify_attributes($tag['attributes'])}/> + HTML; + } else { + $head .= <<stringify_attributes($tag['attributes'])}>{$tag['value']} + HTML; + } + } + + $head .= $this->rawContent . ''; + + // reset head for next render + $this->title = null; + $this->tags = []; + $this->rawContent = ''; + + return $head; + } + + public function title(string $title): self + { + $this->title = $title; + return $this->meta('title', $title) + ->og('title', $title) + ->twitter('title', $title); + } + + public function description(string $desc): self + { + return $this->meta('description', $desc) + ->og('description', $desc) + ->twitter('description', $desc); + } + + public function image(string $url, string $card = 'summary_large_image'): self + { + return $this->og('image', $url) + ->twitter('card', $card) + ->twitter('image', $url); + } + + public function canonical(string $url): self + { + return $this->tag('link', null, [ + 'rel' => 'canonical', + 'href' => $url, + ]); + } + + public function twitter(string $name, string $value): self + { + $this->meta("twitter:{$name}", $value); + return $this; + } + + /** + * @param array $attributes + */ + public function tag(string $name, ?string $value = null, array $attributes = []): self + { + $this->tags[] = [ + 'name' => $name, + 'value' => $value, + 'attributes' => $attributes, + ]; + + return $this; + } + + public function meta(string $name, string $content): self + { + $this->tag('meta', null, [ + 'name' => $name, + 'content' => $content, + ]); + + return $this; + } + + public function og(string $name, string $content): self + { + $this->meta('og:' . $name, $content); + + return $this; + } + + public function appendRawContent(string $content): self + { + $this->rawContent .= $content; + + return $this; + } + + /** + * @param array $attributes + */ + private function stringify_attributes(array $attributes): string + { + return stringify_attributes($attributes); + } +} diff --git a/app/Libraries/NoteObject.php b/app/Libraries/NoteObject.php index b69f164a..2154d8e6 100644 --- a/app/Libraries/NoteObject.php +++ b/app/Libraries/NoteObject.php @@ -3,33 +3,28 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Libraries; -use ActivityPub\Objects\NoteObject as ActivityPubNoteObject; -use App\Entities\Status; +use App\Entities\Post; +use Modules\Fediverse\Objects\NoteObject as FediverseNoteObject; -class NoteObject extends ActivityPubNoteObject +class NoteObject extends FediverseNoteObject { /** - * @param Status $status + * @param Post $post */ - public function __construct($status) + public function __construct($post) { - parent::__construct($status); + parent::__construct($post); - if ($status->episode_id) { + if ($post->episode_id) { $this->content = - '' . - $status->episode->title . - '
' . - $status->message_html; + '' . $post->episode->title . '
' . $post->message_html; } } } diff --git a/app/Libraries/PodcastActor.php b/app/Libraries/PodcastActor.php index 3eef392d..f07a2311 100644 --- a/app/Libraries/PodcastActor.php +++ b/app/Libraries/PodcastActor.php @@ -3,15 +3,15 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Libraries; -use ActivityPub\Objects\ActorObject; use App\Entities\Podcast; +use Modules\Fediverse\Objects\ActorObject; class PodcastActor extends ActorObject { @@ -37,12 +37,13 @@ class PodcastActor extends ActorObject $category = ''; if ($podcast->category->parent_id !== null) { - $category .= $podcast->category->parent->apple_category . ' > '; + $category .= $podcast->category->parent->apple_category . ' › '; } + $category .= $podcast->category->apple_category; $this->category = $category; - $this->episodes = url_to('podcast-episodes', $podcast->name); + $this->episodes = url_to('podcast-episodes', esc($podcast->handle)); } } diff --git a/app/Libraries/PodcastEpisode.php b/app/Libraries/PodcastEpisode.php index 9a8a2002..cbd260b9 100644 --- a/app/Libraries/PodcastEpisode.php +++ b/app/Libraries/PodcastEpisode.php @@ -3,15 +3,19 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Libraries; -use ActivityPub\Core\ObjectType; +use App\Entities\Actor; use App\Entities\Episode; +use CodeIgniter\I18n\Time; +use Modules\Fediverse\Core\ObjectType; +use Modules\Media\Entities\Chapters; +use Modules\Media\Entities\Transcript; class PodcastEpisode extends ObjectType { @@ -42,43 +46,49 @@ class PodcastEpisode extends ObjectType $this->id = $episode->link; $this->description = [ - 'type' => 'Note', - 'mediaType' => 'text/markdown', - 'content' => $episode->description_markdown, + 'type' => 'Note', + 'mediaType' => 'text/markdown', + 'content' => $episode->description_markdown, 'contentMap' => [ $episode->podcast->language_code => $episode->description_html, ], ]; $this->image = [ - 'type' => 'Image', - 'mediaType' => $episode->image_mimetype, - 'url' => $episode->image->url, + 'type' => 'Image', + 'mediaType' => $episode->cover->file_mimetype, + 'url' => $episode->cover->feed_url, ]; // add audio file $this->audio = [ - 'id' => $episode->audio_file_url, - 'type' => 'Audio', - 'name' => $episode->title, - 'size' => $episode->audio_file_size, - 'duration' => $episode->audio_file_duration, - 'url' => [ - 'href' => $episode->audio_file_url, - 'type' => 'Link', - 'mediaType' => $episode->audio_file_mimetype, + 'id' => $episode->audio_url, + 'type' => 'Audio', + 'name' => esc($episode->title), + 'size' => $episode->audio->file_size, + 'duration' => $episode->audio->duration, + 'url' => [ + 'href' => $episode->audio_url, + 'type' => 'Link', + 'mediaType' => $episode->audio->file_mimetype, ], - 'transcript' => $episode->transcript_file_url, - 'chapters' => $episode->chapters_file_url, ]; - $this->comments = url_to('episode-comments', $episode->podcast->name, $episode->slug); + if ($episode->transcript instanceof Transcript) { + $this->audio['transcript'] = $episode->transcript->file_url; + } - if ($episode->published_at !== null) { + if ($episode->chapters instanceof Chapters) { + $this->audio['chapters'] = $episode->chapters->file_url; + } + + $this->comments = url_to('episode-comments', $episode->podcast->handle, $episode->slug); + + if ($episode->published_at instanceof Time) { $this->published = $episode->published_at->format(DATE_W3C); } - if ($episode->podcast->actor !== null) { + if ($episode->podcast->actor instanceof Actor) { $this->attributedTo = $episode->podcast->actor->uri; if ($episode->podcast->actor->followers_url) { diff --git a/app/Libraries/Router.php b/app/Libraries/Router.php index 3f59a70b..5ce2c227 100644 --- a/app/Libraries/Router.php +++ b/app/Libraries/Router.php @@ -7,16 +7,19 @@ declare(strict_types=1); * * It introduces the alternate-content option for a route. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Libraries; -use CodeIgniter\Router\Exceptions\RedirectException; +use CodeIgniter\Exceptions\PageNotFoundException; +use CodeIgniter\HTTP\Exceptions\RedirectException; +use CodeIgniter\Router\Exceptions\RouterException; use CodeIgniter\Router\Router as CodeIgniterRouter; -use Config\Services; +use Config\Routing; +use Override; class Router extends CodeIgniterRouter { @@ -27,11 +30,10 @@ class Router extends CodeIgniterRouter * @param string $uri The URI path to compare against the routes * * @return boolean Whether the route was matched or not. - * @throws RedirectException */ + #[Override] protected function checkRoutes(string $uri): bool { - /** @noRector RemoveExtraParametersRector */ $routes = $this->collection->getRoutes($this->collection->getHTTPVerb()); // Don't waste any time @@ -39,62 +41,70 @@ class Router extends CodeIgniterRouter return false; } - $uri = $uri === '/' ? $uri : ltrim($uri, '/ '); + $uri = $uri === '/' ? $uri : trim($uri, '/ '); // Loop through the route array looking for wildcards - foreach ($routes as $key => $val) { - // Reset localeSegment - $localeSegment = null; + foreach ($routes as $routeKey => $handler) { + $routeKey = $routeKey === '/' ? $routeKey : ltrim((string) $routeKey, '/ '); - $key = $key === '/' ? $key : ltrim($key, '/ '); - - $matchedKey = $key; + $matchedKey = $routeKey; // Are we dealing with a locale? - if (str_contains($key, '{locale}')) { - $localeSegment = array_search( - '{locale}', - preg_split('~[\/]*((^[a-zA-Z0-9])|\(([^()]*)\))*[\/]+~m', $key), - true, - ); - - // Replace it with a regex so it - // will actually match. - $key = str_replace('/', '\/', $key); - $key = str_replace('{locale}', '[^\/]+', $key); + if (str_contains($routeKey, '{locale}')) { + $routeKey = str_replace('{locale}', '[^/]+', $routeKey); } // Does the RegEx match? - if (preg_match('#^' . $key . '$#u', $uri, $matches)) { + if (preg_match('#^' . $routeKey . '$#u', $uri, $matches)) { $this->matchedRouteOptions = $this->collection->getRoutesOptions($matchedKey); // Is this route supposed to redirect to another? - if ($this->collection->isRedirect($key)) { + if ($this->collection->isRedirect($routeKey)) { + // replacing matched route groups with references: post/([0-9]+) -> post/$1 + $redirectTo = preg_replace_callback('/(\([^\(]+\))/', static function (): string { + static $i = 1; + + return '$' . $i++; + }, (string) (is_array($handler) ? key($handler) : $handler)); + throw new RedirectException( - is_array($val) ? key($val) : $val, - $this->collection->getRedirectCode($key), + preg_replace('#^' . $routeKey . '$#u', (string) $redirectTo, $uri), + $this->collection->getRedirectCode($routeKey), ); } + // Store our locale so CodeIgniter object can // assign it to the Request. - if (isset($localeSegment)) { - // The following may be inefficient, but doesn't upset NetBeans :-/ - $temp = explode('/', $uri); - $this->detectedLocale = $temp[$localeSegment]; + if (str_contains($matchedKey, '{locale}')) { + preg_match( + '#^' . str_replace('{locale}', '(?[^/]+)', $matchedKey) . '$#u', + $uri, + $matched, + ); + + if ($this->collection->shouldUseSupportedLocalesOnly() + && ! in_array($matched['locale'], config('App')->supportedLocales, true)) { + // Throw exception to prevent the autorouter, if enabled, + // from trying to find a route + throw PageNotFoundException::forLocaleNotSupported($matched['locale']); + } + + $this->detectedLocale = $matched['locale']; + unset($matched); } // Are we using Closures? If so, then we need // to collect the params into an array // so it can be passed to the controller method later. - if (! is_string($val) && is_callable($val)) { - $this->controller = $val; + if (! is_string($handler) && is_callable($handler)) { + $this->controller = $handler; // Remove the original string from the matches array array_shift($matches); $this->params = $matches; - $this->matchedRoute = [$matchedKey, $val]; + $this->setMatchedRoute($matchedKey, $handler); return true; } @@ -107,10 +117,15 @@ class Router extends CodeIgniterRouter array_key_exists('alternate-content', $this->matchedRouteOptions) && is_array($this->matchedRouteOptions['alternate-content']) ) { - $request = Services::request(); - $negotiate = Services::negotiator(); + $request = service('request'); + $negotiate = service('negotiator'); - $acceptHeader = $request->getHeader('Accept') + // Accept header is mandatory + if ($request->header('Accept') === null) { + break; + } + + $acceptHeader = $request->header('Accept') ->getValue(); $parsedHeader = $negotiate->parseHeader($acceptHeader); @@ -119,61 +134,100 @@ class Router extends CodeIgniterRouter $expectedContentType = $parsedHeader[0]; foreach ($supported as $available) { if ( - $negotiate->callMatch($expectedContentType, $available, true) + ! $negotiate->callMatch($expectedContentType, $available, true) ) { - if ( - array_key_exists( - 'namespace', - $this->matchedRouteOptions[ - 'alternate-content' - ][$available], - ) - ) { - $this->collection->setDefaultNamespace( - $this->matchedRouteOptions[ - 'alternate-content' - ][$available]['namespace'], - ); - } - $val = - $this->collection->getDefaultNamespace() . - $this->directory . - $this->matchedRouteOptions['alternate-content'][ - $available - ]['controller-method']; - - // no need to continue loop as $val has been overwritten - break; + continue; } + + if ( + array_key_exists( + 'namespace', + $this->matchedRouteOptions[ + 'alternate-content' + ][$available], + ) + ) { + $this->collection->setDefaultNamespace( + $this->matchedRouteOptions[ + 'alternate-content' + ][$available]['namespace'], + ); + } + + $handler = + $this->collection->getDefaultNamespace() . + $this->directory . + $this->matchedRouteOptions['alternate-content'][ + $available + ]['controller-method']; + + // no need to continue loop as $handle has been overwritten + break; } } - // Are we using the default method for back-references? + // Are we using Closures? If so, then we need + // to collect the params into an array + // so it can be passed to the controller method later. + if (! is_string($handler) && is_callable($handler)) { + $this->controller = $handler; - // Support resource route when function with subdirectory - // ex: $routes->resource('Admin/Admins'); - if ( - str_contains($val, '$') && - str_contains($key, '(') && - str_contains($key, '/') - ) { - $replacekey = str_replace('/(.*)', '', $key); - $val = preg_replace('#^' . $key . '$#u', $val, $uri); - $val = str_replace($replacekey, str_replace('/', '\\', $replacekey), $val); - } elseif (str_contains($val, '$') && str_contains($key, '(')) { - $val = preg_replace('#^' . $key . '$#u', $val, $uri); - } elseif (str_contains($val, '/')) { - [$controller, $method] = explode('::', $val); + // Remove the original string from the matches array + array_shift($matches); - // Only replace slashes in the controller, not in the method. - $controller = str_replace('/', '\\', $controller); + $this->params = $matches; - $val = $controller . '::' . $method; + $this->setMatchedRoute($matchedKey, $handler); + + return true; } - $this->setRequest(explode('/', $val)); + if (str_contains((string) $handler, '::')) { + [$controller, $methodAndParams] = explode('::', (string) $handler); + } else { + $controller = $handler; + $methodAndParams = ''; + } - $this->matchedRoute = [$matchedKey, $val]; + // Checks `/` in controller name + if (str_contains((string) $controller, '/')) { + throw RouterException::forInvalidControllerName($handler); + } + + if (str_contains((string) $handler, '$') && str_contains($routeKey, '(')) { + // Checks dynamic controller + if (str_contains((string) $controller, '$')) { + throw RouterException::forDynamicController($handler); + } + + if (config(Routing::class)->multipleSegmentsOneParam === false) { + // Using back-references + $segments = explode( + '/', + (string) preg_replace('#\A' . $routeKey . '\z#u', (string) $handler, $uri), + ); + } else { + if (str_contains($methodAndParams, '/')) { + [$method, $handlerParams] = explode('/', $methodAndParams, 2); + $params = explode('/', $handlerParams); + $handlerSegments = array_merge([$controller . '::' . $method], $params); + } else { + $handlerSegments = [$handler]; + } + + $segments = []; + + foreach ($handlerSegments as $segment) { + $segments[] = $this->replaceBackReferences($segment, $matches); + } + } + } else { + $segments = explode('/', (string) $handler); + } + + $this->setRequest($segments); + + $this->setMatchedRoute($matchedKey, $handler); return true; } diff --git a/app/Libraries/RssFeed.php b/app/Libraries/RssFeed.php new file mode 100644 index 00000000..631c80f1 --- /dev/null +++ b/app/Libraries/RssFeed.php @@ -0,0 +1,122 @@ +%s", + $this::ATOM_NAMESPACE, + $this::ITUNES_NAMESPACE, + $this::PODCAST_NAMESPACE, + $contents, + )); + } + + /** + * Adds a child with $value inside CDATA + * + * @param string $name — The name of the child element to add. + * @param string $value — [optional] If specified, the value of the child element. + * @param string|null $namespace [optional] If specified, the namespace to which the child element belongs. + * + * @return static The addChild method returns a SimpleXMLElement object representing the child added to the XML node. + */ + public function addChildWithCDATA(string $name, string $value = '', ?string $namespace = null): static + { + $newChild = parent::addChild($name, null, $namespace); + $node = dom_import_simplexml($newChild); + $no = $node->ownerDocument; + if ($no instanceof DOMDocument) { + $node->appendChild($no->createCDATASection($value)); + } + + return $newChild; + } + + /** + * Adds a child element to the XML node with escaped $value if specified. Override of addChild method as + * SimpleXMLElement's addChild method doesn't escape ampersand + * + * @param string $name — The name of the child element to add. + * @param string $value — [optional] If specified, the value of the child element. + * @param string $namespace [optional] If specified, the namespace to which the child element belongs. + * @param boolean $escape [optional] The value is escaped by default, can be set to false. + * + * @return static The addChild method returns a SimpleXMLElement object representing the child added to the XML node. + */ + #[Override] + public function addChild($name, $value = null, $namespace = null, $escape = true): static + { + $newChild = parent::addChild($name, null, $namespace); + $node = dom_import_simplexml($newChild); + $no = $node->ownerDocument; + $value = $escape ? esc($value ?? '') : $value ?? ''; + if (! $no instanceof DOMDocument) { + return $newChild; + } + + $node->appendChild($no->createTextNode($value)); + + return $newChild; + } + + /** + * Add RssFeed code into a RssFeed + * + * adapted from: https://stackoverflow.com/a/23527002 + * + * @param self|array $nodes + */ + public function appendNodes(self|array $nodes): void + { + if (! is_array($nodes)) { + $nodes = [$nodes]; + } + + foreach ($nodes as $element) { + $namespaces = $element->getNamespaces(); + $namespace = array_first($namespaces) ?? null; + + if (trim((string) $element) === '') { + $simpleRSS = $this->addChild($element->getName(), null, $namespace); + } else { + $simpleRSS = $this->addChild($element->getName(), (string) $element, $namespace); + } + + foreach ($element->children() as $child) { + $simpleRSS->appendNodes($child); + } + + foreach ($element->attributes() as $name => $value) { + $simpleRSS->addAttribute($name, (string) $value); + } + } + } +} diff --git a/app/Libraries/SimpleRSSElement.php b/app/Libraries/SimpleRSSElement.php deleted file mode 100644 index 84944700..00000000 --- a/app/Libraries/SimpleRSSElement.php +++ /dev/null @@ -1,61 +0,0 @@ -ownerDocument; - $node->appendChild($no->createCDATASection($value)); - } - - return $newChild; - } - - /** - * Adds a child element to the XML node with escaped $value if specified. Override of addChild method as - * SimpleXMLElement's addChild method doesn't escape ampersand - * - * @param string $name — The name of the child element to add. - * @param string $value — [optional] If specified, the value of the child element. - * @param string $namespace [optional] If specified, the namespace to which the child element belongs. - * - * @return static The addChild method returns a SimpleXMLElement object representing the child added to the XML node. - */ - public function addChild($name, $value = null, $namespace = null) - { - $newChild = parent::addChild($name, '', $namespace); - - if ($newChild !== null) { - $node = dom_import_simplexml($newChild); - $no = $node->ownerDocument; - $node->appendChild($no->createTextNode((string) esc($value))); - } - - return $newChild; - } -} diff --git a/app/Libraries/ViewComponents/Component.php b/app/Libraries/ViewComponents/Component.php new file mode 100644 index 00000000..eaf9744a --- /dev/null +++ b/app/Libraries/ViewComponents/Component.php @@ -0,0 +1,91 @@ + + */ + protected array $props = []; + + /** + * @var array + */ + protected array $casts = []; + + protected ?string $slot = null; + + /** + * @var array + */ + protected array $attributes = []; + + /** + * @param array $attributes + */ + public function __construct(array $attributes) + { + // overwrite default attributes if set + $this->attributes = [...$this->attributes, ...$attributes]; + + if ($attributes !== []) { + $this->hydrate($attributes); + } + } + + /** + * @param array $attributes + */ + public function hydrate(array $attributes): void + { + foreach ($attributes as $name => $value) { + $method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name))); + if (is_callable([$this, $method])) { + $this->{$method}($value); + } else { + if (array_key_exists($name, $this->casts)) { + $value = match ($this->casts[$name]) { + 'boolean' => $value === 'true', + 'number' => (int) $value, + 'array' => json_decode(htmlspecialchars_decode($value), true), + default => $value, + }; + } + + $this->{$name} = $value; + } + + // remove from attributes + if (in_array($name, $this->props, true)) { + unset($this->attributes[$name]); + } + } + + unset($this->attributes['slot']); + } + + public function mergeClass(string $class): void + { + if (! array_key_exists('class', $this->attributes)) { + $this->attributes['class'] = $class; + } else { + $this->attributes['class'] .= ' ' . $class; + } + } + + public function getStringifiedAttributes(): string + { + return stringify_attributes($this->attributes); + } + + #[Override] + public function render(): string + { + return static::class . ': RENDER METHOD NOT IMPLEMENTED'; + } +} diff --git a/app/Libraries/ViewComponents/ComponentInterface.php b/app/Libraries/ViewComponents/ComponentInterface.php new file mode 100644 index 00000000..397bee87 --- /dev/null +++ b/app/Libraries/ViewComponents/ComponentInterface.php @@ -0,0 +1,10 @@ +config = config('ViewComponents'); + } + + public function render(string $output): string + { + // Try to locate any custom tags, with PascalCase names like: Button, Label, etc. + service('timer') + ->start('self-closing'); + $output = $this->renderSelfClosingTags($output); + service('timer') + ->stop('self-closing'); + + service('timer') + ->start('paired-tags'); + $output = $this->renderPairedTags($output); + service('timer') + ->stop('paired-tags'); + + return $output; + } + + /** + * Finds and renders self-closing tags, i.e. + */ + private function renderSelfClosingTags(string $output): string + { + // Pattern borrowed and adapted from Laravel's ComponentTagCompiler + // Should match any Component tags + $pattern = "/ + < + \\s* + x[-\\:](?[\\w\\-\\:\\.]*) + \\s* + (? + (?: + \\s+ + (?: + (?: + \\{\\{\\s*\\\$attributes(?:[^}]+?)?\\s*\\}\\} + ) + | + (?: + [\\w\\-:.@]+ + ( + = + (?: + \\\"[^\\\"]*\\\" + | + \\'[^\\']*\\' + | + [^\\'\\\"=<>]+ + ) + )? + ) + ) + )* + \\s* + ) + \\/> + /x"; + + /* + $matches[0] = full tags matched + $matches[name] = tag name + $matches[attributes] = array of attribute string (class="foo") + */ + return preg_replace_callback($pattern, function (array $match): string { + $view = $this->locateView($match['name']); + $attributes = $this->parseAttributes($match['attributes']); + + $component = $this->factory($match['name'], $view, $attributes); + + return $component instanceof Component + ? $component->render() + : $this->renderView($view, $attributes); + }, $output) ?? ''; + } + + private function renderPairedTags(string $output): string + { + // ini_set('pcre.backtrack_limit', '-1'); + $pattern = '/<\s*x[-\:](?[\w\-\:\.]*?)(?(\s*[\w\-]+\s*=\s*(\'[^\']*\'|\"[^\"]*\"))+\s*)>(?.*)<\/\s*x-\1\s*>/uiUsm'; + + /* + $matches[0] = full tags matched and all of its content + $matches[name] = pascal cased tag name + $matches[attributes] = string of tag attributes (class="foo") + $matches[slot] = the content inside the tags + */ + return preg_replace_callback($pattern, function (array $match): string { + $view = $this->locateView($match['name']); + $attributes = $this->parseAttributes($match['attributes']); + $attributes['slot'] = $match['slot']; + + $component = $this->factory($match['name'], $view, $attributes); + + return $component instanceof Component + ? $component->render() + : $this->renderView($view, $attributes); + }, $output) ?? (string) preg_last_error(); + } + + /** + * Locate the view file used to render the component. The file's name must match the name of the component. + * + * Looks for class and view file components in the current module before checking the default app module + */ + private function locateView(string $name): string + { + // TODO: Is there a better way to locate components local to current module? + $pathsToDiscover = []; + $lookupPaths = $this->config->lookupPaths; + $pathsToDiscover = array_values($lookupPaths); + $pathsToDiscover[] = $this->config->defaultLookupPath; + + $namePath = str_replace('.', '/', $name); + + foreach ($pathsToDiscover as $basePath) { + // Look for a class component first + $fileKey = $basePath . $this->config->componentsDirectory . '/' . $namePath . '.php'; + + if (is_file($fileKey)) { + return $fileKey; + } + + $snakeCaseName = strtolower(preg_replace('~(?config->componentsDirectory . '/' . $snakeCaseName . '.php'; + + if (is_file($fileKey)) { + return $fileKey; + } + } + + throw new RuntimeException("View not found for component: {$name}"); + } + + /** + * Parses a string to grab any key/value pairs, HTML attributes. + * + * @return array + */ + private function parseAttributes(string $attributeString): array + { + // Pattern borrowed from Laravel's ComponentTagCompiler + $pattern = '/ + (?[\w\-:.@]+) + ( + = + (? + ( + \"[^\"]+\" + | + \\\'[^\\\']+\\\' + | + [^\s>]+ + ) + ) + )? + /x'; + + if (! preg_match_all($pattern, $attributeString, $matches, PREG_SET_ORDER)) { + return []; + } + + $attributes = []; + /** + * @var array $match + */ + foreach ($matches as $match) { + $attributes[$match['attribute']] = $this->stripQuotes($match['value']); + } + + return $attributes; + } + + /** + * Attempts to locate the view and/or class that will be used to render this component. By default, the only thing + * that is needed is a view, but a Component class can also be found if more power is needed. + * + * If a class is used, the name is expected to be Component.php + * + * @param array $attributes + */ + private function factory(string $name, string $view, array $attributes): ?Component + { + // Locate the class in the same folder as the view + $class = $name . '.php'; + $fileKey = str_replace($name . '.php', $class, $view); + + if ($fileKey === '') { + return null; + } + + if (! file_exists($fileKey)) { + return null; + } + + $className = service('locator') + ->getClassname($fileKey); + + if (! class_exists($className)) { + return null; + } + + return new $className($attributes); + } + + /** + * Renders the view when no corresponding class has been found. + * + * @param array $data + */ + private function renderView(string $view, array $data): string + { + return (static function (string $view, $data): string { + extract($data); + ob_start(); + eval('?>' . file_get_contents($view)); + return ob_get_clean() ?: ''; + })($view, $data); + } + + /** + * Removes surrounding quotes from a string. + */ + private function stripQuotes(string $string): string + { + return trim($string, "\'\""); + } +} diff --git a/app/Libraries/ViewComponents/Config/Services.php b/app/Libraries/ViewComponents/Config/Services.php new file mode 100644 index 00000000..b7a1c74d --- /dev/null +++ b/app/Libraries/ViewComponents/Config/Services.php @@ -0,0 +1,31 @@ +render($html); + } + + /** + * Factory method to create a new instance of ComponentRenderer + */ + private static function factory(): ComponentRenderer + { + if (! self::$components instanceof ComponentRenderer) { + self::$components = new ComponentRenderer(); + } + + return self::$components; + } +} diff --git a/app/Libraries/ViewComponents/Exceptions/ComponentNotFoundException.php b/app/Libraries/ViewComponents/Exceptions/ComponentNotFoundException.php new file mode 100644 index 00000000..5b7aaa76 --- /dev/null +++ b/app/Libraries/ViewComponents/Exceptions/ComponentNotFoundException.php @@ -0,0 +1,12 @@ + + */ + public array $themes = [ + 'app' => 'cp_app', + 'admin' => 'cp_admin', + 'install' => 'cp_install', + 'auth' => 'cp_auth', + ]; +} diff --git a/app/Libraries/ViewThemes/Theme.php b/app/Libraries/ViewThemes/Theme.php new file mode 100644 index 00000000..b1b9b008 --- /dev/null +++ b/app/Libraries/ViewThemes/Theme.php @@ -0,0 +1,97 @@ +> + */ + protected static array $info = []; + + public function __construct() + { + $this->config = config('Themes'); + } + + /** + * Sets the active theme. + */ + public static function setTheme(string $theme): void + { + static::$currentTheme = $theme; + } + + /** + * Returns the path to the specified theme folder. If no theme is provided, will use the current theme. + */ + public static function path(?string $theme = null): string + { + if ($theme === null) { + $theme = static::current(); + } + + // Ensure we've pulled the theme info + if (static::$info === []) { + static::$info = self::available(); + } + + foreach (static::$info as $info) { + if ($info['name'] === $theme) { + return $info['path']; + } + } + + return ''; + } + + /** + * Returns the name of the active theme. + */ + public static function current(): string + { + return static::$currentTheme ?? static::$defaultTheme; + } + + /** + * Returns an array of all available themes and the paths to their directories. + * + * @return array> + */ + public static function available(): array + { + $themes = []; + + $config = config('Themes'); + + foreach ($config->themes as $name => $folder) { + $themes[] = [ + 'name' => $name, + 'path' => $config->themesDirectory . '/' . $folder . '/', + ]; + } + + return $themes; + } +} diff --git a/app/Libraries/Vite.php b/app/Libraries/Vite.php deleted file mode 100644 index b088f66b..00000000 --- a/app/Libraries/Vite.php +++ /dev/null @@ -1,118 +0,0 @@ - - */ - protected ?array $manifestData = null; - - /** - * @var array - */ - protected ?array $manifestCSSData = null; - - public function asset(string $path, string $type): string - { - if (ENVIRONMENT !== 'production') { - return $this->loadDev($path, $type); - } - - // @phpstan-ignore-next-line - return $this->loadProd($path, $type); - } - - private function loadDev(string $path, string $type): string - { - return $this->getHtmlTag("http://localhost:3000/assets/{$path}", $type); - } - - private function loadProd(string $path, string $type): string - { - if ($type === 'css') { - if ($this->manifestCSSData === null) { - $cacheName = 'vite-manifest-css'; - if (! ($cachedManifestCSS = cache($cacheName))) { - if (($manifestCSSContent = file_get_contents($this->manifestCSSPath)) !== false) { - $cachedManifestCSS = json_decode($manifestCSSContent, true); - cache() - ->save($cacheName, $cachedManifestCSS, DECADE); - } else { - // ERROR when getting the manifest-css file - $manifestCSSPath = $this->manifestCSSPath; - die("Could not load Vite's
{$manifestCSSPath}
file."); - } - } - $this->manifestCSSData = $cachedManifestCSS; - } - - if (array_key_exists($path, $this->manifestCSSData)) { - return $this->getHtmlTag('/assets/' . $this->manifestCSSData[$path]['file'], 'css'); - } - } - - if ($this->manifestData === null) { - $cacheName = 'vite-manifest'; - if (! ($cachedManifest = cache($cacheName))) { - if (($manifestContents = file_get_contents($this->manifestPath)) !== false) { - $cachedManifest = json_decode($manifestContents, true); - cache() - ->save($cacheName, $cachedManifest, DECADE); - } else { - // ERROR when retrieving the manifest file - $manifestPath = $this->manifestPath; - die("Could not load Vite's
{$manifestPath}
file."); - } - } - $this->manifestData = $cachedManifest; - } - - $html = ''; - if (array_key_exists($path, $this->manifestData)) { - $manifestElement = $this->manifestData[$path]; - - // import css dependencies if any - if (array_key_exists('css', $manifestElement)) { - foreach ($manifestElement['css'] as $cssFile) { - $html .= $this->getHtmlTag('/assets/' . $cssFile, 'css'); - } - } - - // import dependencies first for faster js loading - if (array_key_exists('imports', $manifestElement)) { - foreach ($manifestElement['imports'] as $importPath) { - if (array_key_exists($importPath, $this->manifestData)) { - $html .= $this->getHtmlTag('/assets/' . $this->manifestData[$importPath]['file'], 'js'); - } - } - } - - $html .= $this->getHtmlTag('/assets/' . $manifestElement['file'], $type); - } - - return $html; - } - - private function getHtmlTag(string $assetUrl, string $type): string - { - return match ($type) { - 'css' => << - CODE_SAMPLE -, - 'js' => << - CODE_SAMPLE -, - default => '', - }; - } -} diff --git a/app/Models/ActorModel.php b/app/Models/ActorModel.php index 8191299a..59369100 100644 --- a/app/Models/ActorModel.php +++ b/app/Models/ActorModel.php @@ -3,20 +3,27 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Models; -use ActivityPub\Models\ActorModel as ActivityPubActorModel; use App\Entities\Actor; +use Modules\Fediverse\Models\ActorModel as FediverseActorModel; +use Override; -class ActorModel extends ActivityPubActorModel +class ActorModel extends FediverseActorModel { /** - * @var string + * @var class-string */ protected $returnType = Actor::class; + + #[Override] + public function getActorById(int $id): ?Actor + { + return $this->find($id); + } } diff --git a/app/Models/CategoryModel.php b/app/Models/CategoryModel.php index 5bfc38aa..2c67efeb 100644 --- a/app/Models/CategoryModel.php +++ b/app/Models/CategoryModel.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -26,12 +26,12 @@ class CategoryModel extends Model protected $primaryKey = 'id'; /** - * @var string[] + * @var list */ protected $allowedFields = ['parent_id', 'code', 'apple_category', 'google_category']; /** - * @var string + * @var class-string */ protected $returnType = Category::class; @@ -64,8 +64,18 @@ class CategoryModel extends Model $options = array_reduce( $categories, - function (array $result, Category $category): array { - $result[$category->id] = lang('Podcast.category_options.' . $category->code); + static function (array $result, Category $category): array { + $label = ''; + if ($category->parent instanceof Category) { + $label = lang('Podcast.category_options.' . $category->parent->code) . ' › '; + } + + $label .= lang('Podcast.category_options.' . $category->code); + + $result[] = [ + 'value' => $category->id, + 'label' => $label, + ]; return $result; }, [], @@ -104,12 +114,11 @@ class CategoryModel extends Model // prepare data for `podcasts_categories` table $data = array_reduce( $categoriesIds, - function (array $result, int $categoryId) use ($podcastId): array { + static function (array $result, int $categoryId) use ($podcastId): array { $result[] = [ - 'podcast_id' => $podcastId, + 'podcast_id' => $podcastId, 'category_id' => $categoryId, ]; - return $result; }, [], diff --git a/app/Models/ClipModel.php b/app/Models/ClipModel.php new file mode 100644 index 00000000..cc5209c9 --- /dev/null +++ b/app/Models/ClipModel.php @@ -0,0 +1,248 @@ + + */ + protected $allowedFields = [ + 'id', + 'podcast_id', + 'episode_id', + 'title', + 'start_time', + 'duration', + 'type', + 'media_id', + 'metadata', + 'status', + 'logs', + 'created_by', + 'updated_by', + 'job_started_at', + 'job_ended_at', + ]; + + protected $returnType = BaseClip::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + public function __construct( + protected string $type = 'audio', + ?ConnectionInterface &$db = null, + ?ValidationInterface $validation = null, + ) { + switch ($type) { + case 'audio': + $this->returnType = Soundbite::class; + break; + case 'video': + $this->returnType = VideoClip::class; + break; + default: + // do nothing, keep default class + break; + } + + parent::__construct($db, $validation); + } + + public function getVideoClipById(int $videoClipId): ?VideoClip + { + $cacheName = "video-clip#{$videoClipId}"; + if (! ($found = cache($cacheName))) { + $clip = $this->find($videoClipId); + + if (! $clip instanceof BaseClip) { + return null; + } + + $found = new VideoClip($clip->toArray()); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Gets scheduled video clips for an episode + * + * @return VideoClip[] + */ + public function getScheduledVideoClips(): array + { + $found = $this->where([ + 'type' => 'video', + 'status' => 'queued', + ]) + ->orderBy('created_at') + ->findAll(); + + foreach ($found as $key => $videoClip) { + $found[$key] = new VideoClip($videoClip->toArray()); + } + + return $found; + } + + public function getRunningVideoClipsCount(): int + { + $result = $this->builder() + ->select('COUNT(*) as `running_count`') + ->where([ + 'type' => 'video', + 'status' => 'running', + ]) + ->get() + ->getResultArray(); + + return (int) $result[0]['running_count']; + } + + public function doesVideoClipExist(VideoClip $videoClip): int | false + { + $result = $this->select('id') + ->builder() + ->where([ + 'podcast_id' => $videoClip->podcast_id, + 'episode_id' => $videoClip->episode_id, + 'start_time' => $videoClip->start_time, + 'duration' => $videoClip->duration, + ]) + ->where('JSON_EXTRACT(`metadata`, "$.format")', $videoClip->format) + ->where('JSON_EXTRACT(`metadata`, "$.theme.name")', $videoClip->theme['name']) + ->get() + ->getResultArray(); + + if ($result === []) { + return false; + } + + return (int) $result[0]['id']; + } + + public function deleteVideoClip(int $clipId): BaseResult | bool + { + $this->clearVideoClipCache($clipId); + + return $this->delete($clipId); + } + + public function getClipCount(int $podcastId, int $episodeId): int + { + return $this + ->where([ + 'podcast_id' => $podcastId, + 'episode_id' => $episodeId, + ]) + ->countAllResults(); + } + + public function clearVideoClipCache(int $clipId): void + { + cache() + ->delete("video-clip#{$clipId}"); + } + + public function getSoundbiteById(int $soundbiteId): ?Soundbite + { + $cacheName = "soundbite#{$soundbiteId}"; + if (! ($found = cache($cacheName))) { + $clip = $this->find($soundbiteId); + + if (! $clip instanceof BaseClip) { + return null; + } + + $found = new Soundbite($clip->toArray()); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Gets all clips for an episode + * + * @return Soundbite[] + */ + public function getEpisodeSoundbites(int $podcastId, int $episodeId): array + { + $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_soundbites"; + if (! ($found = cache($cacheName))) { + $found = $this->where([ + 'episode_id' => $episodeId, + 'podcast_id' => $podcastId, + 'type' => 'audio', + ]) + ->orderBy('start_time') + ->findAll(); + + foreach ($found as $key => $soundbite) { + $found[$key] = new Soundbite($soundbite->toArray()); + } + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function deleteSoundbite(int $podcastId, int $episodeId, int $clipId): BaseResult | bool + { + $this->clearSoundbiteCache($podcastId, $episodeId, $clipId); + + return $this->delete($clipId); + } + + public function clearSoundbiteCache(int $podcastId, int $episodeId, int $clipId): void + { + cache() + ->delete("podcast#{$podcastId}_episode#{$episodeId}_soundbites"); + cache() + ->delete("soundbite#{$clipId}"); + } +} diff --git a/app/Models/CreditModel.php b/app/Models/CreditModel.php index b8b73fdd..23342d4c 100644 --- a/app/Models/CreditModel.php +++ b/app/Models/CreditModel.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -21,7 +21,7 @@ class CreditModel extends Model protected $table = 'credits'; /** - * @var string + * @var class-string */ protected $returnType = Credit::class; } diff --git a/app/Models/EpisodeCommentModel.php b/app/Models/EpisodeCommentModel.php new file mode 100644 index 00000000..60582586 --- /dev/null +++ b/app/Models/EpisodeCommentModel.php @@ -0,0 +1,335 @@ + + */ + protected $returnType = EpisodeComment::class; + + /** + * @var string + */ + protected $table = 'episode_comments'; + + /** + * @var string[] + */ + protected $uuidFields = ['id', 'in_reply_to_id']; + + /** + * @var list + */ + protected $allowedFields = [ + 'id', + 'uri', + 'episode_id', + 'actor_id', + 'in_reply_to_id', + 'message', + 'message_html', + 'likes_count', + 'replies_count', + 'created_at', + 'created_by', + ]; + + /** + * @var list + */ + protected $beforeInsert = ['setCommentId']; + + public function getCommentById(string $commentId): ?EpisodeComment + { + $cacheName = "comment#{$commentId}"; + if (! ($found = cache($cacheName))) { + $found = $this->find($commentId); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function addComment(EpisodeComment $comment, bool $registerActivity = true): bool|int|object|string + { + $this->db->transStart(); + + if (! ($newCommentId = $this->insert($comment, true))) { + $this->db->transRollback(); + + // Couldn't insert comment + return false; + } + + if ($comment->in_reply_to_id === null) { + new EpisodeModel() + ->builder() + ->where('id', $comment->episode_id) + ->increment('comments_count'); + } else { + new self() + ->builder() + ->where('id', service('uuid')->fromString($comment->in_reply_to_id)->getBytes()) + ->increment('replies_count'); + } + + if ($registerActivity) { + // set post id and uri to construct NoteObject + $comment->id = $newCommentId; + $comment->uri = url_to( + 'episode-comment', + esc($comment->actor->username), + $comment->episode->slug, + $comment->id, + ); + + $createActivity = new CreateActivity(); + $createActivity + ->set('actor', $comment->actor->uri) + ->set('object', new CommentObject($comment)); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Create', + $comment->actor_id, + null, + null, + $createActivity->toJSON(), + $comment->created_at, + 'queued', + ); + + $createActivity->set('id', url_to('activity', esc($comment->actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $createActivity->toJSON(), + ]); + } + + $this->db->transComplete(); + + $this->clearCache($comment); + + return $newCommentId; + } + + public function removeComment(EpisodeComment $comment, bool $registerActivity = true): BaseResult | bool + { + $this->db->transStart(); + + // remove all replies + foreach ($comment->replies as $reply) { + $this->removeComment($reply); + } + + if ($registerActivity) { + $deleteActivity = new DeleteActivity(); + $tombstoneObject = new TombstoneObject(); + $tombstoneObject->set('id', $comment->uri); + $deleteActivity + ->set('actor', $comment->actor->uri) + ->set('object', $tombstoneObject); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Delete', + $comment->actor_id, + null, + null, + $deleteActivity->toJSON(), + Time::now(), + 'queued', + ); + + $deleteActivity->set('id', url_to('activity', esc($comment->actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $deleteActivity->toJSON(), + ]); + } + + $result = model(self::class, false) + ->delete($comment->id); + + if ($comment->in_reply_to_id === null) { + model('EpisodeModel', false)->builder() + ->where('id', $comment->episode_id) + ->decrement('comments_count'); + } else { + new self() + ->builder() + ->where('id', service('uuid')->fromString($comment->in_reply_to_id)->getBytes()) + ->decrement('replies_count'); + } + + $this->clearCache($comment); + + $this->db->transComplete(); + + return $result; + } + + /** + * Retrieves all published posts for a given episode ordered by publication date + * + * @return EpisodeComment[] + */ + public function getEpisodeComments(int $episodeId): array + { + // TODO: merge with replies from posts linked to episode linked + $episodeCommentsBuilder = $this->builder(); + $episodeComments = $episodeCommentsBuilder->select('*, 0 as is_private, 0 as is_from_post') + ->where([ + 'episode_id' => $episodeId, + 'in_reply_to_id' => null, + ]) + ->getCompiledSelect(); + + $postModel = new PostModel(); + $episodePostsRepliesBuilder = $postModel->builder(); + $episodePostsReplies = $episodePostsRepliesBuilder->select( + 'id, uri, episode_id, actor_id, in_reply_to_id, message, message_html, favourites_count as likes_count, replies_count, published_at as created_at, created_by, is_private, 1 as is_from_post', + ) + ->whereIn('in_reply_to_id', static function (BaseBuilder $builder) use (&$episodeId): BaseBuilder { + return $builder->select('id') + ->from('fediverse_posts') + ->where([ + 'episode_id' => $episodeId, + 'in_reply_to_id' => null, + ]); + }) + ->where('`created_at` <= UTC_TIMESTAMP()', null, false); + + // do not get private replies if public + if (! can_user_interact()) { + $episodePostsRepliesBuilder->where('is_private', false); + } + + $episodePostsReplies = $episodePostsRepliesBuilder->getCompiledSelect(); + + /** @var BaseResult $allEpisodeComments */ + $allEpisodeComments = $this->db->query( + $episodeComments . ' UNION ' . $episodePostsReplies . ' ORDER BY created_at ASC', + ); + + return $this->convertUuidFieldsToStrings( + $allEpisodeComments->getCustomResultObject($this->tempReturnType), + $this->tempReturnType, + ); + } + + /** + * Retrieves all replies for a given comment + * + * @return EpisodeComment[] + */ + public function getCommentReplies(string $commentId): array + { + // TODO: get all replies for a given comment + return $this->where('in_reply_to_id', $this->uuid->fromString($commentId)->getBytes()) + ->orderBy('created_at', 'ASC') + ->findAll(); + } + + public function resetLikesCount(): int | false + { + $commentsLikesCount = $this->db->table('likes') + ->select('comment_id as id, COUNT(*) as `likes_count`') + ->groupBy('id') + ->get() + ->getResultArray(); + + if ($commentsLikesCount !== []) { + $this->uuidUseBytes = false; + return $this->updateBatch($commentsLikesCount, 'id'); + } + + return 0; + } + + public function resetRepliesCount(): int | false + { + $commentsRepliesCount = $this->builder() + ->select('episode_comments.id, COUNT(*) as `replies_count`') + ->join('episode_comments as c2', 'episode_comments.id = c2.in_reply_to_id') + ->groupBy('episode_comments.id') + ->get() + ->getResultArray(); + + if ($commentsRepliesCount !== []) { + $this->uuidUseBytes = false; + return $this->updateBatch($commentsRepliesCount, 'id'); + } + + return 0; + } + + /** + * @param array> $data + * @return array> + */ + protected function setCommentId(array $data): array + { + $uuid4 = $this->uuid->{$this->uuidVersion}(); + $data['data']['id'] = $uuid4->toString(); + + if (! isset($data['data']['uri'])) { + $actor = model('ActorModel', false) + ->getActorById((int) $data['data']['actor_id']); + $episode = model('EpisodeModel', false) + ->find((int) $data['data']['episode_id']); + + if (! $episode instanceof Episode) { + return $data; + } + + if (! $actor instanceof Actor) { + return $data; + } + + $data['data']['uri'] = url_to('episode-comment', $actor->username, $episode->slug, $uuid4->toString()); + } + + return $data; + } + + protected function clearCache(EpisodeComment $comment): void + { + cache() + ->deleteMatching("comment#{$comment->id}*"); + + // delete podcast and episode pages cache + cache() + ->deleteMatching("podcast-{$comment->episode->podcast->handle}*"); + cache() + ->deleteMatching('page_podcast#' . $comment->episode->podcast_id . '*'); + cache() + ->deleteMatching('page_episode#' . $comment->episode_id . '*'); + } +} diff --git a/app/Models/EpisodeModel.php b/app/Models/EpisodeModel.php index 11b885b3..c1ec3a02 100644 --- a/app/Models/EpisodeModel.php +++ b/app/Models/EpisodeModel.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -11,9 +11,13 @@ declare(strict_types=1); namespace App\Models; use App\Entities\Episode; -use CodeIgniter\Model; +use CodeIgniter\Database\BaseBuilder; +use CodeIgniter\Database\BaseResult; +use CodeIgniter\I18n\Time; +use Michalsn\Uuid\UuidModel; +use Ramsey\Uuid\Lazy\LazyUuidFromString; -class EpisodeModel extends Model +class EpisodeModel extends UuidModel { /** * TODO: remove, shouldn't be here @@ -22,65 +26,59 @@ class EpisodeModel extends Model */ public static $themes = [ 'light-transparent' => [ - 'style' => - 'background-color: #fff; background-image: linear-gradient(45deg, #ccc 12.5%, transparent 12.5%, transparent 50%, #ccc 50%, #ccc 62.5%, transparent 62.5%, transparent 100%); background-size: 5.66px 5.66px;', + 'style' => 'background-color: #fff; background-image: linear-gradient(45deg, #ccc 12.5%, transparent 12.5%, transparent 50%, #ccc 50%, #ccc 62.5%, transparent 62.5%, transparent 100%); background-size: 5.66px 5.66px;', 'background' => 'transparent', - 'text' => '#000', - 'inverted' => '#fff', + 'text' => '#000', + 'inverted' => '#fff', ], 'light' => [ - 'style' => 'background-color: #fff;', + 'style' => 'background-color: #fff;', 'background' => '#fff', - 'text' => '#000', - 'inverted' => '#fff', + 'text' => '#000', + 'inverted' => '#fff', ], 'dark-transparent' => [ - 'style' => - 'background-color: #001f1a; background-image: linear-gradient(45deg, #888 12.5%, transparent 12.5%, transparent 50%, #888 50%, #888 62.5%, transparent 62.5%, transparent 100%); background-size: 5.66px 5.66px;', + 'style' => 'background-color: #001f1a; background-image: linear-gradient(45deg, #888 12.5%, transparent 12.5%, transparent 50%, #888 50%, #888 62.5%, transparent 62.5%, transparent 100%); background-size: 5.66px 5.66px;', 'background' => 'transparent', - 'text' => '#fff', - 'inverted' => '#000', + 'text' => '#fff', + 'inverted' => '#000', ], 'dark' => [ - 'style' => 'background-color: #001f1a;', - 'background' => '#001f1a', - 'text' => '#fff', - 'inverted' => '#000', + 'style' => 'background-color: #001f1a;', + 'background' => '#313131', + 'text' => '#fff', + 'inverted' => '#000', ], ]; + /** + * @var string[] + */ + protected $uuidFields = ['preview_id']; + /** * @var string */ protected $table = 'episodes'; /** - * @var string - */ - protected $primaryKey = 'id'; - - /** - * @var string[] + * @var list */ protected $allowedFields = [ 'id', 'podcast_id', + 'preview_id', 'guid', 'title', 'slug', - 'audio_file_path', - 'audio_file_duration', - 'audio_file_mimetype', - 'audio_file_size', - 'audio_file_header_size', + 'audio_id', 'description_markdown', 'description_html', - 'image_path', - 'image_mimetype', - 'transcript_file_path', - 'transcript_file_remote_url', - 'chapters_file_path', - 'chapters_file_remote_url', + 'cover_id', + 'transcript_id', + 'transcript_remote_url', + 'chapters_id', + 'chapters_remote_url', 'parental_advisory', 'number', 'season_number', @@ -89,25 +87,21 @@ class EpisodeModel extends Model 'location_name', 'location_geo', 'location_osm', - 'custom_rss', - 'favourites_total', - 'reblogs_total', - 'statuses_total', + 'is_published_on_hubs', + 'downloads_count', + 'posts_count', + 'comments_count', + 'is_premium', 'published_at', 'created_by', 'updated_by', ]; /** - * @var string + * @var class-string */ protected $returnType = Episode::class; - /** - * @var bool - */ - protected $useSoftDeletes = true; - /** * @var bool */ @@ -117,45 +111,45 @@ class EpisodeModel extends Model * @var array */ protected $validationRules = [ - 'podcast_id' => 'required', - 'title' => 'required', - 'slug' => 'required|regex_match[/^[a-zA-Z0-9\-]{1,191}$/]', - 'audio_file_path' => 'required', - 'description_markdown' => 'required', - 'number' => 'is_natural_no_zero|permit_empty', - 'season_number' => 'is_natural_no_zero|permit_empty', - 'type' => 'required', - 'transcript_file_remote_url' => 'valid_url|permit_empty', - 'chapters_file_remote_url' => 'valid_url|permit_empty', - 'published_at' => 'valid_date|permit_empty', - 'created_by' => 'required', - 'updated_by' => 'required', + 'podcast_id' => 'required', + 'title' => 'required', + 'slug' => 'required|regex_match[/^[a-zA-Z0-9\-]{1,128}$/]', + 'audio_id' => 'required', + 'description_markdown' => 'required', + 'number' => 'is_natural_no_zero|permit_empty', + 'season_number' => 'is_natural_no_zero|permit_empty', + 'type' => 'required', + 'transcript_remote_url' => 'valid_url_strict|permit_empty', + 'chapters_remote_url' => 'valid_url_strict|permit_empty', + 'published_at' => 'valid_date|permit_empty', + 'created_by' => 'required', + 'updated_by' => 'required', ]; /** - * @var string[] + * @var list */ protected $afterInsert = ['writeEnclosureMetadata', 'clearCache']; /** - * @var string[] + * @var list */ protected $afterUpdate = ['clearCache', 'writeEnclosureMetadata']; /** - * @var string[] + * @var list */ protected $beforeDelete = ['clearCache']; - public function getEpisodeBySlug(string $podcastName, string $episodeSlug): ?Episode + public function getEpisodeBySlug(string $podcastHandle, string $episodeSlug): ?Episode { - $cacheName = "podcast-{$podcastName}_episode-{$episodeSlug}"; + $cacheName = "podcast-{$podcastHandle}_episode-{$episodeSlug}"; if (! ($found = cache($cacheName))) { $found = $this->select('episodes.*') ->join('podcasts', 'podcasts.id = episodes.podcast_id') ->where('slug', $episodeSlug) - ->where('podcasts.name', $podcastName) - ->where('`published_at` <= NOW()', null, false) + ->where('podcasts.handle', $podcastHandle) + ->where('`' . $this->db->getPrefix() . 'episodes`.`published_at` <= UTC_TIMESTAMP()', null, false) ->first(); cache() @@ -191,7 +185,7 @@ class EpisodeModel extends Model 'id' => $episodeId, ]) ->where('podcast_id', $podcastId) - ->where('`published_at` <= NOW()', null, false) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->first(); cache() @@ -201,6 +195,38 @@ class EpisodeModel extends Model return $found; } + public function getEpisodeByPreviewId(string $previewId): ?Episode + { + $cacheName = "podcast_episode-preview#{$previewId}"; + if (! ($found = cache($cacheName))) { + $builder = $this->where([ + 'preview_id' => $this->uuid->fromString($previewId) + ->getBytes(), + ]); + + $found = $builder->first(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function setEpisodePreviewId(int $episodeId): string|false + { + /** @var LazyUuidFromString $uuid */ + $uuid = $this->uuid->{$this->uuidVersion}(); + + if (! $this->update($episodeId, [ + 'preview_id' => $uuid, + ])) { + return false; + } + + return (string) $uuid; + } + /** * Gets all episodes for a podcast ordered according to podcast type Filtered depending on year or season * @@ -209,8 +235,8 @@ class EpisodeModel extends Model public function getPodcastEpisodes( int $podcastId, string $podcastType, - string $year = null, - string $season = null + ?string $year = null, + ?string $season = null, ): array { $cacheName = implode( '_', @@ -225,6 +251,7 @@ class EpisodeModel extends Model $where['YEAR(published_at)'] = $year; $where['season_number'] = null; } + if ($season) { $where['season_number'] = $season; } @@ -232,12 +259,12 @@ class EpisodeModel extends Model if ($podcastType === 'serial') { // podcast is serial $found = $this->where($where) - ->where('`published_at` <= NOW()', null, false) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->orderBy('season_number DESC, number ASC') ->findAll(); } else { $found = $this->where($where) - ->where('`published_at` <= NOW()', null, false) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->orderBy('published_at', 'DESC') ->findAll(); } @@ -245,18 +272,24 @@ class EpisodeModel extends Model $secondsToNextUnpublishedEpisode = $this->getSecondsToNextUnpublishedEpisode($podcastId); cache() - ->save( - $cacheName, - $found, - $secondsToNextUnpublishedEpisode - ? $secondsToNextUnpublishedEpisode - : DECADE, - ); + ->save($cacheName, $found, $secondsToNextUnpublishedEpisode ?: DECADE); } return $found; } + /** + * Returns number of episodes of a podcast + */ + public function getPodcastEpisodesCount(int $podcastId): int|string + { + return $this + ->where([ + 'podcast_id' => $podcastId, + ]) + ->countAllResults(); + } + /** * Returns the timestamp difference in seconds between the next episode to publish and the current timestamp Returns * false if there's no episode to publish @@ -265,11 +298,12 @@ class EpisodeModel extends Model */ public function getSecondsToNextUnpublishedEpisode(int $podcastId): int | false { - $result = $this->select('TIMESTAMPDIFF(SECOND, NOW(), `published_at`) as timestamp_diff') + $result = $this->builder() + ->select('TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), `published_at`) as timestamp_diff') ->where([ 'podcast_id' => $podcastId, ]) - ->where('`published_at` > NOW()', null, false) + ->where('`published_at` > UTC_TIMESTAMP()', null, false) ->orderBy('published_at', 'asc') ->get() ->getResultArray(); @@ -279,22 +313,139 @@ class EpisodeModel extends Model : false; } + public function getCurrentSeasonNumber(int $podcastId): ?int + { + $result = $this->builder() + ->selectMax('season_number', 'current_season_number') + ->where('podcast_id', $podcastId) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray(); + + return $result[0]['current_season_number'] ? (int) $result[0]['current_season_number'] : null; + } + + public function getNextEpisodeNumber(int $podcastId, ?int $seasonNumber): int + { + $result = $this->builder() + ->selectMax('number', 'next_episode_number') + ->where([ + 'podcast_id' => $podcastId, + 'season_number' => $seasonNumber, + ]) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray(); + + return (int) $result[0]['next_episode_number'] + 1; + } + + /** + * @return array{number_of_seasons: int, number_of_episodes: int, first_published_at?: Time} + */ + public function getPodcastStats(int $podcastId): array + { + $result = $this->builder() + ->select( + 'COUNT(DISTINCT season_number) as number_of_seasons, COUNT(*) as number_of_episodes, MIN(published_at) as first_published_at', + ) + ->where('podcast_id', $podcastId) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray(); + + $stats = [ + 'number_of_seasons' => (int) $result[0]['number_of_seasons'], + 'number_of_episodes' => (int) $result[0]['number_of_episodes'], + ]; + + if ($result[0]['first_published_at'] !== null) { + $stats['first_published_at'] = new Time($result[0]['first_published_at']); + } + + return $stats; + } + + public function resetCommentsCount(): int | false + { + $episodeCommentsCount = new EpisodeCommentModel() + ->builder() + ->select('episode_id, COUNT(*) as `comments_count`') + ->where('in_reply_to_id') + ->groupBy('episode_id') + ->getCompiledSelect(); + + $episodePostsRepliesCount = new PostModel() + ->builder() + ->select('fediverse_posts.episode_id as episode_id, COUNT(*) as `comments_count`') + ->join('fediverse_posts as fp', 'fediverse_posts.id = fp.in_reply_to_id') + ->where('fediverse_posts.in_reply_to_id') + ->where('fediverse_posts.episode_id IS NOT') + ->groupBy('fediverse_posts.episode_id') + ->getCompiledSelect(); + + /** @var BaseResult $query */ + $query = $this->db->query( + 'SELECT `episode_id` as `id`, SUM(`comments_count`) as `comments_count` FROM (' . $episodeCommentsCount . ' UNION ALL ' . $episodePostsRepliesCount . ') x GROUP BY `episode_id`', + ); + + $countsPerEpisodeId = $query->getResultArray(); + + if ($countsPerEpisodeId !== []) { + return new self() + ->updateBatch($countsPerEpisodeId, 'id'); + } + + return 0; + } + + public function resetPostsCount(): int | false + { + $episodePostsCount = $this->builder() + ->select('episodes.id, COUNT(*) as `posts_count`') + ->join('fediverse_posts', 'episodes.id = fediverse_posts.episode_id') + ->where('in_reply_to_id') + ->groupBy('episodes.id') + ->get() + ->getResultArray(); + + if ($episodePostsCount !== []) { + return $this->updateBatch($episodePostsCount, 'id'); + } + + return 0; + } + /** * @param mixed[] $data * - * @return array> + * @return mixed[] */ public function clearCache(array $data): array { - $episode = (new self())->find(is_array($data['id']) ? $data['id'][0] : $data['id']); + /** @var int|null $episodeId */ + $episodeId = is_array($data['id']) ? $data['id'][0] : $data['id']; + + if ($episodeId === null) { + // Multiple episodes have been updated, do nothing + return $data; + } + + /** @var ?Episode $episode */ + $episode = new self() + ->find($episodeId); + + if (! $episode instanceof Episode) { + return $data; + } // delete podcast cache cache() ->deleteMatching("podcast#{$episode->podcast_id}*"); cache() - ->deleteMatching("podcast-{$episode->podcast->name}*"); + ->deleteMatching("podcast-{$episode->podcast->handle}*"); cache() - ->delete("podcast_episode#{$episode->id}"); + ->deleteMatching('podcast_episode*'); cache() ->deleteMatching("page_podcast#{$episode->podcast_id}*"); cache() @@ -305,16 +456,85 @@ class EpisodeModel extends Model return $data; } + public function doesPodcastHavePremiumEpisodes(int $podcastId): bool + { + return $this->builder() + ->where([ + 'podcast_id' => $podcastId, + 'is_premium' => true, + ]) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->countAllResults() > 0; + } + + public function fullTextSearch(string $query): ?BaseBuilder + { + $prefix = $this->db->getPrefix(); + $episodeTable = $prefix . $this->builder()->getTable(); + + $podcastModel = (new PodcastModel()); + + $podcastTable = $podcastModel->db->getPrefix() . $podcastModel->builder()->getTable(); + + $this->builder() + ->select('' . $episodeTable . '.*') + ->select(' + ' . $this->getFullTextMatchClauseForEpisodes($episodeTable, $query) . ' as episodes_score, + ' . $podcastModel->getFullTextMatchClauseForPodcasts($podcastTable, $query) . ' as podcasts_score, + ') + ->select("{$podcastTable}.created_at AS podcast_created_at") + ->select( + "{$podcastTable}.title as podcast_title, {$podcastTable}.handle as podcast_handle, {$podcastTable}.description_markdown as podcast_description_markdown", + ) + ->join($podcastTable, "{$podcastTable} on {$podcastTable}.id = {$episodeTable}.podcast_id") + ->where(' + (' . + $this->getFullTextMatchClauseForEpisodes($episodeTable, $query) + . 'OR' . + $podcastModel->getFullTextMatchClauseForPodcasts($podcastTable, $query) + . ') + ', ); + + return $this->builder; + } + + public function getFullTextMatchClauseForEpisodes(string $table, string $value): string + { + return ' + MATCH ( + ' . $table . '.title, + ' . $table . '.description_markdown, + ' . $table . '.slug, + ' . $table . '.location_name + ) + AGAINST(' . $this->db->escape($value) . ') + '; + } + /** * @param mixed[] $data * - * @return array> + * @return mixed[] */ protected function writeEnclosureMetadata(array $data): array { - helper('id3'); + /** @var int|null $episodeId */ + $episodeId = is_array($data['id']) ? $data['id'][0] : $data['id']; - $episode = (new self())->find(is_array($data['id']) ? $data['id'][0] : $data['id']); + if ($episodeId === null) { + // Multiple episodes have been updated, do nothing + return $data; + } + + /** @var ?Episode $episode */ + $episode = new self() + ->find($episodeId); + + if (! $episode instanceof Episode) { + return $data; + } + + helper('id3'); write_audio_file_tags($episode); diff --git a/app/Models/LanguageModel.php b/app/Models/LanguageModel.php index 83e68e59..b68a9197 100644 --- a/app/Models/LanguageModel.php +++ b/app/Models/LanguageModel.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -26,12 +26,12 @@ class LanguageModel extends Model protected $primaryKey = 'id'; /** - * @var string[] + * @var list */ protected $allowedFields = ['code', 'native_name']; /** - * @var string + * @var class-string */ protected $returnType = Language::class; @@ -55,8 +55,11 @@ class LanguageModel extends Model $options = array_reduce( $languages, - function (array $result, Language $language): array { - $result[$language->code] = $language->native_name; + static function (array $result, Language $language): array { + $result[] = [ + 'value' => $language->code, + 'label' => $language->native_name, + ]; return $result; }, [], diff --git a/app/Models/LikeModel.php b/app/Models/LikeModel.php new file mode 100644 index 00000000..f3f382de --- /dev/null +++ b/app/Models/LikeModel.php @@ -0,0 +1,173 @@ + + */ + protected $allowedFields = ['actor_id', 'comment_id']; + + /** + * @var class-string + */ + protected $returnType = Like::class; + + /** + * @var bool + */ + protected $useTimestamps = true; + + protected $updatedField = ''; + + public function addLike(Actor $actor, EpisodeComment $comment, bool $registerActivity = true): void + { + $this->db->transStart(); + + $this->insert([ + 'actor_id' => $actor->id, + 'comment_id' => $comment->id, + ]); + + new EpisodeCommentModel() + ->builder() + ->where('id', service('uuid')->fromString($comment->id)->getBytes()) + ->increment('likes_count'); + + if ($registerActivity) { + $likeActivity = new LikeActivity(); + $likeActivity->set('actor', $actor->uri) + ->set('object', $comment->uri); + + $activityId = model('ActivityModel') + ->newActivity( + 'Like', + $actor->id, + null, + null, + $likeActivity->toJSON(), + $comment->created_at, + 'queued', + ); + + $likeActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel') + ->update($activityId, [ + 'payload' => $likeActivity->toJSON(), + ]); + } + + $this->db->transComplete(); + } + + public function removeLike(Actor $actor, EpisodeComment $comment, bool $registerActivity = true): void + { + $this->db->transStart(); + + new EpisodeCommentModel() + ->builder() + ->where('id', service('uuid') ->fromString($comment->id) ->getBytes()) + ->decrement('likes_count'); + + $this->where([ + 'actor_id' => $actor->id, + 'comment_id' => service('uuid') + ->fromString($comment->id) + ->getBytes(), + ]) + ->delete(); + + if ($registerActivity) { + $undoActivity = new UndoActivity(); + // FIXME: get like activity associated with the deleted like + $activity = model('ActivityModel') + ->where([ + 'type' => 'Like', + 'actor_id' => $actor->id, + ]) + ->first(); + + if (! $activity instanceof Activity) { + // no like activity found, do nothing + return; + } + + $likeActivity = new LikeActivity(); + $likeActivity + ->set('id', url_to('activity', esc($actor->username), $activity->id)) + ->set('actor', $actor->uri) + ->set('object', $comment->uri); + + $undoActivity + ->set('actor', $actor->uri) + ->set('object', $likeActivity); + + $activityId = model('ActivityModel') + ->newActivity( + 'Undo', + $actor->id, + null, + null, + $undoActivity->toJSON(), + $comment->created_at, + 'queued', + ); + + $undoActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel') + ->update($activityId, [ + 'payload' => $undoActivity->toJSON(), + ]); + } + + $this->db->transComplete(); + } + + /** + * Adds or removes likes from database + */ + public function toggleLike(Actor $actor, EpisodeComment $comment): void + { + if ( + $this->where([ + 'actor_id' => $actor->id, + 'comment_id' => service('uuid') + ->fromString($comment->id) + ->getBytes(), + ])->first() instanceof Like + ) { + $this->removeLike($actor, $comment); + } else { + $this->addLike($actor, $comment); + } + } +} diff --git a/app/Models/PageModel.php b/app/Models/PageModel.php index 1b3b6284..f9a9eb5a 100644 --- a/app/Models/PageModel.php +++ b/app/Models/PageModel.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -26,19 +26,19 @@ class PageModel extends Model protected $primaryKey = 'id'; /** - * @var string[] + * @var list */ protected $allowedFields = ['id', 'title', 'slug', 'content_markdown', 'content_html']; /** - * @var string + * @var class-string */ protected $returnType = Page::class; /** * @var bool */ - protected $useSoftDeletes = true; + protected $useSoftDeletes = false; /** * @var bool @@ -49,26 +49,25 @@ class PageModel extends Model * @var array */ protected $validationRules = [ - 'title' => 'required', - 'slug' => - 'required|regex_match[/^[a-zA-Z0-9\-]{1,191}$/]|is_unique[pages.slug,id,{id}]', + 'title' => 'required', + 'slug' => 'required|regex_match[/^[a-zA-Z0-9\-]{1,128}$/]|is_unique[pages.slug,id,{id}]', 'content_markdown' => 'required', ]; /** - * @var string[] + * @var list */ protected $afterInsert = ['clearCache']; /** * Before update because slug or title might change * - * @var string[] + * @var list */ protected $beforeUpdate = ['clearCache']; /** - * @var string[] + * @var list */ protected $beforeDelete = ['clearCache']; diff --git a/app/Models/PersonModel.php b/app/Models/PersonModel.php index 7b9aca80..705ad50a 100644 --- a/app/Models/PersonModel.php +++ b/app/Models/PersonModel.php @@ -3,16 +3,14 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Models; -use App\Entities\Image; use App\Entities\Person; -use CodeIgniter\Database\Query; use CodeIgniter\Model; class PersonModel extends Model @@ -28,21 +26,20 @@ class PersonModel extends Model protected $primaryKey = 'id'; /** - * @var string[] + * @var list */ protected $allowedFields = [ 'id', 'full_name', 'unique_name', 'information_url', - 'image_path', - 'image_mimetype', + 'avatar_id', 'created_by', 'updated_by', ]; /** - * @var string + * @var class-string */ protected $returnType = Person::class; @@ -60,28 +57,26 @@ class PersonModel extends Model * @var array */ protected $validationRules = [ - 'full_name' => 'required', - 'unique_name' => - 'required|regex_match[/^[a-z0-9\-]{1,191}$/]|is_unique[persons.unique_name,id,{id}]', - 'image_path' => 'required', - 'created_by' => 'required', - 'updated_by' => 'required', + 'full_name' => 'required', + 'unique_name' => 'required|regex_match[/^[a-z0-9\-]{1,32}$/]|is_unique[persons.unique_name,id,{id}]', + 'created_by' => 'required', + 'updated_by' => 'required', ]; /** - * @var string[] + * @var list */ protected $afterInsert = ['clearCache']; /** * clear cache before update if by any chance, the person name changes, so will the person link * - * @var string[] + * @var list */ protected $beforeUpdate = ['clearCache']; /** - * @var string[] + * @var list */ protected $beforeDelete = ['clearCache']; @@ -113,7 +108,7 @@ class PersonModel extends Model $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}_roles"; if (! ($found = cache($cacheName))) { - $found = $this + $found = $this->builder() ->select('episodes_persons.person_group as group, episodes_persons.person_role as role') ->join('episodes_persons', 'persons.id = episodes_persons.person_id') ->where('persons.id', $personId) @@ -125,7 +120,7 @@ class PersonModel extends Model $cacheName = "podcast#{$podcastId}_person#{$personId}_roles"; if (! ($found = cache($cacheName))) { - $found = $this + $found = $this->builder() ->select('podcasts_persons.person_group as group, podcasts_persons.person_role as role') ->join('podcasts_persons', 'persons.id = podcasts_persons.person_id') ->where('persons.id', $personId) @@ -150,8 +145,11 @@ class PersonModel extends Model $this->select('`id`, `full_name`') ->orderBy('`full_name`', 'ASC') ->findAll(), - function ($result, $person) { - $result[$person->id] = $person->full_name; + static function (array $result, Person $person): array { + $result[] = [ + 'value' => $person->id, + 'label' => $person->full_name, + ]; return $result; }, [], @@ -179,9 +177,10 @@ class PersonModel extends Model if (! ($options = cache($cacheName))) { foreach ($personsTaxonomy as $group_key => $group) { foreach ($group['roles'] as $role_key => $role) { - $options[ - "{$group_key},{$role_key}" - ] = "{$group['label']} › {$role['label']}"; + $options[] = [ + 'value' => sprintf('%s,%s', $group_key, $role_key), + 'label' => sprintf('%s › %s', $group['label'], $role['label']), + ]; } } @@ -195,12 +194,13 @@ class PersonModel extends Model public function addPerson(string $fullName, ?string $informationUrl, string $image): int | bool { $person = new Person([ - 'full_name' => $fullName, - 'unique_name' => slugify($fullName), + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'full_name' => $fullName, + 'unique_name' => slugify($fullName), 'information_url' => $informationUrl, - 'image' => new Image(download_file($image)), - 'created_by' => user_id(), - 'updated_by' => user_id(), + 'image' => download_file($image), + ]); return $this->insert($person); @@ -213,15 +213,15 @@ class PersonModel extends Model { $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_persons"; if (! ($found = cache($cacheName))) { - $found = $this + $this->builder() ->select( - 'persons.*, episodes_persons.podcast_id as podcast_id, episodes_persons.episode_id as episode_id' + 'persons.*, episodes_persons.podcast_id as podcast_id, episodes_persons.episode_id as episode_id', ) ->distinct() ->join('episodes_persons', 'persons.id = episodes_persons.person_id') ->where('episodes_persons.episode_id', $episodeId) - ->orderby('persons.full_name') - ->findAll(); + ->orderby('persons.full_name'); + $found = $this->findAll(); cache() ->save($cacheName, $found, DECADE); @@ -237,13 +237,13 @@ class PersonModel extends Model { $cacheName = "podcast#{$podcastId}_persons"; if (! ($found = cache($cacheName))) { - $found = $this + $this->builder() ->select('persons.*, podcasts_persons.podcast_id as podcast_id') ->distinct() ->join('podcasts_persons', 'persons.id=podcasts_persons.person_id') ->where('podcasts_persons.podcast_id', $podcastId) - ->orderby('persons.full_name') - ->findAll(); + ->orderby('persons.full_name'); + $found = $this->findAll(); cache() ->save($cacheName, $found, DECADE); @@ -257,38 +257,35 @@ class PersonModel extends Model int $episodeId, int $personId, string $groupSlug, - string $roleSlug - ): bool | Query { + string $roleSlug, + ): bool { return $this->db->table('episodes_persons') ->insert([ - 'podcast_id' => $podcastId, - 'episode_id' => $episodeId, - 'person_id' => $personId, + 'podcast_id' => $podcastId, + 'episode_id' => $episodeId, + 'person_id' => $personId, 'person_group' => $groupSlug, - 'person_role' => $roleSlug, + 'person_role' => $roleSlug, ]); } - public function addPodcastPerson( - int $podcastId, - int $personId, - string $groupSlug, - string $roleSlug - ): bool | Query { + public function addPodcastPerson(int $podcastId, int $personId, string $groupSlug, string $roleSlug): bool + { return $this->db->table('podcasts_persons') + ->ignore(true) ->insert([ - 'podcast_id' => $podcastId, - 'person_id' => $personId, + 'podcast_id' => $podcastId, + 'person_id' => $personId, 'person_group' => $groupSlug, - 'person_role' => $roleSlug, + 'person_role' => $roleSlug, ]); } /** * Add persons to podcast * - * @param array $personIds - * @param array $roles + * @param int[] $personIds + * @param string[] $roles * * @return bool|int Number of rows inserted or FALSE on failure */ @@ -300,26 +297,30 @@ class PersonModel extends Model cache() ->delete("podcast#{$podcastId}_persons"); - (new PodcastModel())->clearCache([ - 'id' => $podcastId, - ]); + new PodcastModel() + ->clearCache([ + 'id' => $podcastId, + ]); $data = []; foreach ($personIds as $personId) { if ($roles === []) { + // add to default group (cast) and role (host), see https://podcastindex.org/namespace/1.0#person $data[] = [ - 'podcast_id' => $podcastId, - 'person_id' => $personId, + 'podcast_id' => $podcastId, + 'person_id' => $personId, + 'person_group' => 'cast', + 'person_role' => 'host', ]; } foreach ($roles as $role) { $groupRole = explode(',', $role); $data[] = [ - 'podcast_id' => $podcastId, - 'person_id' => $personId, + 'podcast_id' => $podcastId, + 'person_id' => $personId, 'person_group' => $groupRole[0], - 'person_role' => $groupRole[1], + 'person_role' => $groupRole[1], ]; } } @@ -339,14 +340,15 @@ class PersonModel extends Model cache()->deleteMatching("podcast#{$podcastId}_person#{$personId}*"); cache() ->delete("podcast#{$podcastId}_persons"); - (new PodcastModel())->clearCache([ - 'id' => $podcastId, - ]); + new PodcastModel() + ->clearCache([ + 'id' => $podcastId, + ]); return $this->db->table('podcasts_persons') ->delete([ 'podcast_id' => $podcastId, - 'person_id' => $personId, + 'person_id' => $personId, ]); } @@ -354,48 +356,49 @@ class PersonModel extends Model * Add persons to episode * * @param int[] $personIds - * @param string[] $groupsRoles + * @param string[] $roles * * @return bool|int Number of rows inserted or FALSE on failure */ - public function addEpisodePersons( - int $podcastId, - int $episodeId, - array $personIds, - array $groupsRoles - ): bool | int { + public function addEpisodePersons(int $podcastId, int $episodeId, array $personIds, array $roles): bool | int + { if ($personIds !== []) { cache() ->delete("podcast#{$podcastId}_episode#{$episodeId}_persons"); - (new EpisodeModel())->clearCache([ - 'id' => $episodeId, - ]); + new EpisodeModel() + ->clearCache([ + 'id' => $episodeId, + ]); $data = []; foreach ($personIds as $personId) { - if ($groupsRoles !== []) { - foreach ($groupsRoles as $groupRole) { - $groupRole = explode(',', $groupRole); - $data[] = [ - 'podcast_id' => $podcastId, - 'episode_id' => $episodeId, - 'person_id' => $personId, - 'person_group' => $groupRole[0], - 'person_role' => $groupRole[1], - ]; - } - } else { + if ($roles === []) { $data[] = [ - 'podcast_id' => $podcastId, - 'episode_id' => $episodeId, - 'person_id' => $personId, + 'podcast_id' => $podcastId, + 'episode_id' => $episodeId, + 'person_id' => $personId, + 'person_group' => 'cast', + 'person_role' => 'host', + ]; + } + + foreach ($roles as $role) { + $groupRole = explode(',', $role); + $data[] = [ + 'podcast_id' => $podcastId, + 'episode_id' => $episodeId, + 'person_id' => $personId, + 'person_group' => $groupRole[0], + 'person_role' => $groupRole[1], ]; } } + return $this->db->table('episodes_persons') ->ignore(true) ->insertBatch($data); } + return 0; } @@ -404,15 +407,16 @@ class PersonModel extends Model cache()->deleteMatching("podcast#{$podcastId}_episode#{$episodeId}_person#{$personId}*"); cache() ->delete("podcast#{$podcastId}_episode#{$episodeId}_persons"); - (new EpisodeModel())->clearCache([ - 'id' => $episodeId, - ]); + new EpisodeModel() + ->clearCache([ + 'id' => $episodeId, + ]); return $this->db->table('episodes_persons') ->delete([ 'podcast_id' => $podcastId, 'episode_id' => $episodeId, - 'person_id' => $personId, + 'person_id' => $personId, ]); } diff --git a/app/Models/PlatformModel.php b/app/Models/PlatformModel.php deleted file mode 100644 index 5eb57279..00000000 --- a/app/Models/PlatformModel.php +++ /dev/null @@ -1,202 +0,0 @@ -baseURL, '/'); - $found = $this->select( - "*, CONCAT('{$baseUrl}/assets/images/platforms/',`type`,'/',`slug`,'.svg') as icon", - )->findAll(); - cache() - ->save('platforms', $found, DECADE); - } - return $found; - } - - public function getPlatform(string $slug): ?Platform - { - $cacheName = "platform-{$slug}"; - if (! ($found = cache($cacheName))) { - $found = $this->where('slug', $slug) - ->first(); - cache() - ->save($cacheName, $found, DECADE); - } - return $found; - } - - public function createPlatform( - string $slug, - string $type, - string $label, - string $homeUrl, - string $submitUrl = null - ): int | false { - $data = [ - 'slug' => $slug, - 'type' => $type, - 'label' => $label, - 'home_url' => $homeUrl, - 'submit_url' => $submitUrl, - ]; - - return $this->insert($data, false); - } - - /** - * @return Platform[] - */ - public function getPlatformsWithLinks(int $podcastId, string $platformType): array - { - if ( - ! ($found = cache("podcast#{$podcastId}_platforms_{$platformType}_withLinks")) - ) { - $found = $this->select( - 'platforms.*, podcasts_platforms.link_url, podcasts_platforms.link_content, podcasts_platforms.is_visible, podcasts_platforms.is_on_embeddable_player', - ) - ->join( - 'podcasts_platforms', - "podcasts_platforms.platform_slug = platforms.slug AND podcasts_platforms.podcast_id = {$podcastId}", - 'left', - ) - ->where('platforms.type', $platformType) - ->findAll(); - - cache() - ->save("podcast#{$podcastId}_platforms_{$platformType}_withLinks", $found, DECADE); - } - - return $found; - } - - /** - * @return Platform[] - */ - public function getPodcastPlatforms(int $podcastId, string $platformType): array - { - $cacheName = "podcast#{$podcastId}_platforms_{$platformType}"; - if (! ($found = cache($cacheName))) { - $found = $this->select( - 'platforms.*, podcasts_platforms.link_url, podcasts_platforms.link_content, podcasts_platforms.is_visible, podcasts_platforms.is_on_embeddable_player', - ) - ->join('podcasts_platforms', 'podcasts_platforms.platform_slug = platforms.slug') - ->where('podcasts_platforms.podcast_id', $podcastId) - ->where('platforms.type', $platformType) - ->findAll(); - - cache() - ->save($cacheName, $found, DECADE); - } - - return $found; - } - - /** - * @param mixed[] $podcastsPlatformsData - */ - public function savePodcastPlatforms( - int $podcastId, - string $platformType, - array $podcastsPlatformsData - ): int | false { - $this->clearCache($podcastId); - - $podcastsPlatformsTable = $this->db->prefixTable('podcasts_platforms'); - $platformsTable = $this->db->prefixTable('platforms'); - - $deleteJoinQuery = <<db->query($deleteJoinQuery, [$podcastId, $platformType]); - - return $this->db - ->table('podcasts_platforms') - ->insertBatch($podcastsPlatformsData); - } - - /** - * @param mixed[] $podcastsPlatformsData - */ - public function createPodcastPlatforms(int $podcastId, array $podcastsPlatformsData): int | false - { - $this->clearCache($podcastId); - - return $this->db - ->table('podcasts_platforms') - ->insertBatch($podcastsPlatformsData); - } - - public function removePodcastPlatform(int $podcastId, string $platformSlug): bool | string - { - $this->clearCache($podcastId); - - return $this->db->table('podcasts_platforms') - ->delete([ - 'podcast_id' => $podcastId, - 'platform_slug' => $platformSlug, - ]); - } - - public function clearCache(int $podcastId): void - { - cache()->deleteMatching("podcast#{$podcastId}_platforms_*"); - - // delete localized podcast page cache - cache() - ->deleteMatching("page_podcast#{$podcastId}*"); - } -} diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php index 739593e7..c64516f1 100644 --- a/app/Models/PodcastModel.php +++ b/app/Models/PodcastModel.php @@ -3,15 +3,15 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace App\Models; +use App\Entities\Actor; use App\Entities\Podcast; -use CodeIgniter\Database\Query; use CodeIgniter\HTTP\URI; use CodeIgniter\Model; use phpseclib\Crypt\RSA; @@ -29,19 +29,17 @@ class PodcastModel extends Model protected $primaryKey = 'id'; /** - * @var string[] + * @var list */ protected $allowedFields = [ 'id', 'guid', 'title', - 'name', + 'handle', 'description_markdown', 'description_html', - 'episode_description_footer_markdown', - 'episode_description_footer_html', - 'image_path', - 'image_mimetype', + 'cover_id', + 'banner_id', 'language_code', 'category_id', 'parental_advisory', @@ -58,25 +56,18 @@ class PodcastModel extends Model 'location_name', 'location_geo', 'location_osm', - 'payment_pointer', - 'custom_rss', - 'partner_id', - 'partner_link_url', - 'partner_image_url', + 'is_published_on_hubs', + 'is_premium_by_default', + 'published_at', 'created_by', 'updated_by', ]; /** - * @var string + * @var class-string */ protected $returnType = Podcast::class; - /** - * @var bool - */ - protected $useSoftDeletes = true; - /** * @var bool */ @@ -86,54 +77,57 @@ class PodcastModel extends Model * @var array */ protected $validationRules = [ - 'title' => 'required', - 'name' => - 'required|regex_match[/^[a-zA-Z0-9\_]{1,191}$/]|is_unique[podcasts.name,id,{id}]', + 'id' => 'permit_empty|is_natural_no_zero', + 'title' => 'required', + 'handle' => 'required|regex_match[/^[a-zA-Z0-9\_]{1,32}$/]|is_unique[podcasts.handle,id,{id}]', 'description_markdown' => 'required', - 'image_path' => 'required', - 'language_code' => 'required', - 'category_id' => 'required', - 'owner_email' => 'required|valid_email', - 'type' => 'required', - 'created_by' => 'required', - 'updated_by' => 'required', + 'cover_id' => 'required', + 'language_code' => 'required', + 'category_id' => 'required', + 'owner_email' => 'required|valid_email', + 'new_feed_url' => 'valid_url_strict|permit_empty', + 'type' => 'required', + 'published_at' => 'valid_date|permit_empty', + 'created_by' => 'required', + 'updated_by' => 'required', ]; /** - * @var string[] + * @var list */ - protected $beforeInsert = ['createPodcastActor']; + protected $beforeInsert = ['setPodcastGUID', 'createPodcastActor']; /** - * @var string[] + * @var list */ protected $afterInsert = ['setActorAvatar']; /** - * @var string[] + * @var list */ protected $afterUpdate = ['updatePodcastActor']; /** * clear cache before update if by any chance, the podcast name changes, so will the podcast link * - * @var string[] + * @var list */ protected $beforeUpdate = ['clearCache']; /** - * @var string[] + * @var list */ protected $beforeDelete = ['clearCache']; - public function getPodcastByName(string $podcastName): ?Podcast + public function getPodcastByHandle(string $podcastHandle): ?Podcast { - $cacheName = "podcast-{$podcastName}"; + $cacheName = "podcast-{$podcastHandle}"; if (! ($found = cache($cacheName))) { - $found = $this->where('name', $podcastName) + $found = $this->where('handle', $podcastHandle) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->first(); cache() - ->save("podcast-{$podcastName}", $found, DECADE); + ->save("podcast-{$podcastHandle}", $found, DECADE); } return $found; @@ -166,18 +160,46 @@ class PodcastModel extends Model return $found; } + /** + * @return Podcast[] + */ + public function getAllPodcasts(?string $orderBy = null): array + { + $prefix = $this->db->getPrefix(); + + if ($orderBy === 'activity') { + $this->builder() + ->select('podcasts.*, MAX(`' . $prefix . 'fediverse_posts`.`published_at`) as max_published_at') + ->join('fediverse_posts', 'fediverse_posts.actor_id = podcasts.actor_id', 'left') + ->groupStart() + ->where( + '`' . $prefix . 'fediverse_posts`.`published_at` <= UTC_TIMESTAMP()', + null, + false, + )->orWhere('fediverse_posts.published_at') + ->groupEnd() + ->groupBy('podcasts.actor_id') + ->orderBy('max_published_at', 'DESC'); + } elseif ($orderBy === 'created_desc') { + $this->orderBy('created_at', 'DESC'); + } elseif ($orderBy === 'created_asc') { + $this->orderBy('created_at', 'ASC'); + } + + return $this->where('`' . $prefix . 'podcasts`.`published_at` <= UTC_TIMESTAMP()', null, false)->findAll(); + } + /** * Gets all the podcasts a given user is contributing to * + * @param string[] $userPodcastIds * @return Podcast[] podcasts */ - public function getUserPodcasts(int $userId): array + public function getUserPodcasts(int $userId, array $userPodcastIds): array { $cacheName = "user{$userId}_podcasts"; if (! ($found = cache($cacheName))) { - $found = $this->select('podcasts.*') - ->join('podcasts_users', 'podcasts_users.podcast_id = podcasts.id') - ->where('podcasts_users.user_id', $userId) + $found = $userPodcastIds === [] ? [] : $this->whereIn('id', $userPodcastIds) ->findAll(); cache() @@ -187,76 +209,18 @@ class PodcastModel extends Model return $found; } - public function addPodcastContributor(int $userId, int $podcastId, int $groupId): Query | bool + public function getContributorGroup(int $userId, int $podcastId): int | false { - cache()->delete("podcast#{$podcastId}_contributors"); + $userPodcast = $this->db + ->table('auth_groups_users') + ->select('user_id, group') + ->where('user_id', $userId) + ->like('group', "podcast#{$podcastId}") + ->get() + ->getResultObject(); - $data = [ - 'user_id' => $userId, - 'podcast_id' => $podcastId, - 'group_id' => $groupId, - ]; - - return $this->db->table('podcasts_users') - ->insert($data); - } - - public function updatePodcastContributor(int $userId, int $podcastId, int $groupId): bool - { - cache()->delete("podcast#{$podcastId}_contributors"); - - return $this->db - ->table('podcasts_users') - ->where([ - 'user_id' => $userId, - 'podcast_id' => $podcastId, - ]) - ->update([ - 'group_id' => $groupId, - ]); - } - - public function removePodcastContributor(int $userId, int $podcastId): string | bool - { - cache()->delete("podcast#{$podcastId}_contributors"); - - return $this->db - ->table('podcasts_users') - ->where([ - 'user_id' => $userId, - 'podcast_id' => $podcastId, - ]) - ->delete(); - } - - public function getContributorGroupId(int $userId, int | string $podcastId): int | false - { - if (! is_numeric($podcastId)) { - // identifier is the podcast name, request must be a join - $userPodcast = $this->db - ->table('podcasts_users') - ->select('group_id, user_id') - ->join('podcasts', 'podcasts.id = podcasts_users.podcast_id') - ->where([ - 'user_id' => $userId, - 'name' => $podcastId, - ]) - ->get() - ->getResultObject(); - } else { - $userPodcast = $this->db - ->table('podcasts_users') - ->select('group_id') - ->where([ - 'user_id' => $userId, - 'podcast_id' => $podcastId, - ]) - ->get() - ->getResultObject(); - } - - return count($userPodcast) > 0 - ? (int) $userPodcast[0]->group_id + return $userPodcast !== [] + ? (int) $userPodcast[0]->group : false; } @@ -269,13 +233,13 @@ class PodcastModel extends Model if (! ($found = cache($cacheName))) { $episodeModel = new EpisodeModel(); $found = $episodeModel + ->builder() ->select('YEAR(published_at) as year, count(*) as number_of_episodes') ->where([ - 'podcast_id' => $podcastId, + 'podcast_id' => $podcastId, 'season_number' => null, - $episodeModel->deletedField => null, ]) - ->where('`published_at` <= NOW()', null, false) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->groupBy('year') ->orderBy('year', 'DESC') ->get() @@ -284,13 +248,7 @@ class PodcastModel extends Model $secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode($podcastId); cache() - ->save( - $cacheName, - $found, - $secondsToNextUnpublishedEpisode - ? $secondsToNextUnpublishedEpisode - : DECADE, - ); + ->save($cacheName, $found, $secondsToNextUnpublishedEpisode ?: DECADE); } return $found; @@ -305,13 +263,13 @@ class PodcastModel extends Model if (! ($found = cache($cacheName))) { $episodeModel = new EpisodeModel(); $found = $episodeModel + ->builder() ->select('season_number, count(*) as number_of_episodes') ->where([ - 'podcast_id' => $podcastId, + 'podcast_id' => $podcastId, 'season_number is not' => null, - $episodeModel->deletedField => null, ]) - ->where('`published_at` <= NOW()', null, false) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->groupBy('season_number') ->orderBy('season_number', 'ASC') ->get() @@ -320,13 +278,7 @@ class PodcastModel extends Model $secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode($podcastId); cache() - ->save( - $cacheName, - $found, - $secondsToNextUnpublishedEpisode - ? $secondsToNextUnpublishedEpisode - : DECADE, - ); + ->save($cacheName, $found, $secondsToNextUnpublishedEpisode ?: DECADE); } return $found; @@ -357,9 +309,13 @@ class PodcastModel extends Model ]; } + $secondsToNextUnpublishedEpisode = new EpisodeModel() + ->getSecondsToNextUnpublishedEpisode($podcastId); + cache() - ->save($cacheName, $defaultQuery, DECADE); + ->save($cacheName, $defaultQuery, $secondsToNextUnpublishedEpisode ?: DECADE); } + return $defaultQuery; } @@ -370,22 +326,27 @@ class PodcastModel extends Model */ public function clearCache(array $data): array { - $podcast = (new self())->getPodcastById(is_array($data['id']) ? $data['id'][0] : $data['id']); + $podcast = new self() + ->find((int) (is_array($data['id']) ? $data['id'][0] : $data['id'])); - if ($podcast !== null) { + // delete cache for users' podcasts + cache() + ->deleteMatching('user*podcasts'); + + if ($podcast instanceof Podcast) { // delete cache all podcast pages cache() ->deleteMatching("page_podcast#{$podcast->id}*"); // delete all cache for podcast actor cache() - ->deleteMatching(config('ActivityPub') ->cachePrefix . "actor#{$podcast->actor_id}*"); + ->deleteMatching(config('Fediverse') ->cachePrefix . "actor#{$podcast->actor_id}*"); // delete model requests cache, includes feed / query / episode lists, etc. cache() ->deleteMatching("podcast#{$podcast->id}*"); cache() - ->delete("podcast-{$podcast->name}"); + ->delete("podcast-{$podcast->handle}"); } // clear cache for every credit page @@ -395,6 +356,19 @@ class PodcastModel extends Model return $data; } + public function getFullTextMatchClauseForPodcasts(string $table, string $value): string + { + return ' + MATCH ( + ' . $table . '.title , + ' . $table . '.description_markdown, + ' . $table . '.handle, + ' . $table . '.location_name + ) + AGAINST(' . $this->db->escape($value) . ') + '; + } + /** * Creates an actor linked to the podcast (Triggered before insert) * @@ -413,25 +387,26 @@ class PodcastModel extends Model $publickey = $rsaKey['publickey']; $url = new URI(base_url()); - $username = $data['data']['name']; + $username = $data['data']['handle']; $domain = $url->getHost() . ($url->getPort() ? ':' . $url->getPort() : ''); - $actorId = (new ActorModel())->insert( - [ - 'uri' => url_to('actor', $username), - 'username' => $username, - 'domain' => $domain, - 'private_key' => $privatekey, - 'public_key' => $publickey, - 'display_name' => $data['data']['title'], - 'summary' => $data['data']['description_html'], - 'inbox_url' => url_to('inbox', $username), - 'outbox_url' => url_to('outbox', $username), - 'followers_url' => url_to('followers', $username), - ], - true, - ); + $actorId = new ActorModel() + ->insert( + [ + 'uri' => url_to('podcast-activity', $username), + 'username' => $username, + 'domain' => $domain, + 'private_key' => $privatekey, + 'public_key' => $publickey, + 'display_name' => $data['data']['title'], + 'summary' => $data['data']['description_html'], + 'inbox_url' => url_to('inbox', $username), + 'outbox_url' => url_to('outbox', $username), + 'followers_url' => url_to('followers', $username), + ], + true, + ); $data['data']['actor_id'] = $actorId; @@ -445,14 +420,23 @@ class PodcastModel extends Model */ protected function setActorAvatar(array $data): array { - $podcast = (new self())->getPodcastById(is_array($data['id']) ? $data['id'][0] : $data['id']); + $podcast = new self() + ->find((int) (is_array($data['id']) ? $data['id'][0] : $data['id'])); - $podcastActor = (new ActorModel())->find($podcast->actor_id); + if ($podcast instanceof Podcast) { + $podcastActor = new ActorModel() + ->find($podcast->actor_id); - $podcastActor->avatar_image_url = $podcast->image->thumbnail_url; - $podcastActor->avatar_image_mimetype = $podcast->image_mimetype; + if (! $podcastActor instanceof Actor) { + return $data; + } - (new ActorModel())->update($podcast->actor_id, $podcastActor); + $podcastActor->avatar_image_url = $podcast->cover->federation_url; + $podcastActor->avatar_image_mimetype = $podcast->cover->federation_mimetype; + + new ActorModel() + ->update($podcast->actor_id, $podcastActor); + } return $data; } @@ -464,23 +448,51 @@ class PodcastModel extends Model */ protected function updatePodcastActor(array $data): array { - $podcast = (new self())->getPodcastById(is_array($data['id']) ? $data['id'][0] : $data['id']); + $podcast = new self() + ->find((int) (is_array($data['id']) ? $data['id'][0] : $data['id'])); - if ($podcast !== null) { + if ($podcast instanceof Podcast) { $actorModel = new ActorModel(); $actor = $actorModel->getActorById($podcast->actor_id); - // update values - $actor->display_name = $podcast->title; - $actor->summary = $podcast->description_html; - $actor->avatar_image_url = $podcast->image->thumbnail_url; - $actor->avatar_image_mimetype = $podcast->image_mimetype; + if ($actor instanceof Actor) { + // update values + $actor->display_name = $podcast->title; + $actor->summary = $podcast->description_html; + $actor->avatar_image_url = $podcast->cover->federation_url; + $actor->avatar_image_mimetype = $podcast->cover->federation_mimetype; + $actor->cover_image_url = get_podcast_banner_url($podcast, 'federation'); + $actor->cover_image_mimetype = get_podcast_banner_mimetype($podcast, 'federation'); - if ($actor->hasChanged()) { - $actorModel->update($actor->id, $actor); + if ($actor->hasChanged()) { + $actorModel->update($actor->id, $actor); + } } } return $data; } + + /** + * @param mixed[] $data + * + * Sets the UUIDv5 for a podcast. For more information, see + * https://podcastindex.org/namespace/1.0#guid + * + * @return mixed[] + */ + protected function setPodcastGUID(array $data): array + { + if (! array_key_exists( + 'guid', + $data['data'], + ) || $data['data']['guid'] === null || $data['data']['guid'] === '') { + $uuid = service('uuid'); + $feedUrl = url_to('podcast-rss-feed', $data['data']['handle']); + // 'ead4c236-bf58-58c6-a2c6-a6b28d128cb6' is the uuid of the podcast namespace + $data['data']['guid'] = $uuid->uuid5('ead4c236-bf58-58c6-a2c6-a6b28d128cb6', $feedUrl)->toString(); + } + + return $data; + } } diff --git a/app/Models/PostModel.php b/app/Models/PostModel.php new file mode 100644 index 00000000..06b0b00a --- /dev/null +++ b/app/Models/PostModel.php @@ -0,0 +1,81 @@ + + */ + protected $returnType = Post::class; + + /** + * @var list + */ + protected $allowedFields = [ + 'id', + 'uri', + 'actor_id', + 'in_reply_to_id', + 'reblog_of_id', + 'episode_id', + 'message', + 'message_html', + 'is_private', + 'favourites_count', + 'reblogs_count', + 'replies_count', + 'created_by', + 'published_at', + ]; + + /** + * Retrieves all published posts for a given episode ordered by publication date + * + * @return Post[] + */ + public function getEpisodePosts(int $episodeId): array + { + return $this->where([ + 'episode_id' => $episodeId, + ]) + ->where('in_reply_to_id') + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'DESC') + ->findAll(); + } + + public function setEpisodeIdForRepliesOfEpisodePosts(): int | false + { + // make sure that posts in reply to episode activities have an episode id + $postsToUpdate = $this->db->table('fediverse_posts as p1') + ->join('fediverse_posts as p2', 'p1.id = p2.in_reply_to_id') + ->select('p2.id, p1.episode_id') + ->where([ + 'p2.in_reply_to_id IS NOT' => null, + 'p2.episode_id' => null, + 'p1.episode_id IS NOT' => null, + ]) + ->get() + ->getResultArray(); + + if ($postsToUpdate !== []) { + $postModel = new self(); + $postModel->uuidUseBytes = false; + return $postModel->updateBatch($postsToUpdate, 'id'); + } + + return 0; + } +} diff --git a/app/Models/SoundbiteModel.php b/app/Models/SoundbiteModel.php deleted file mode 100644 index e17140b0..00000000 --- a/app/Models/SoundbiteModel.php +++ /dev/null @@ -1,128 +0,0 @@ -delete([ - 'podcast_id' => $podcastId, - 'episode_id' => $episodeId, - 'id' => $soundbiteId, - ]); - } - - /** - * Gets all soundbites for an episode - * - * @return Soundbite[] - */ - public function getEpisodeSoundbites(int $podcastId, int $episodeId): array - { - $cacheName = "podcast#{$podcastId}_episode#{$episodeId}_soundbites"; - if (! ($found = cache($cacheName))) { - $found = $this->where([ - 'episode_id' => $episodeId, - 'podcast_id' => $podcastId, - ]) - ->orderBy('start_time') - ->findAll(); - cache() - ->save($cacheName, $found, DECADE); - } - return $found; - } - - /** - * @param array> $data - * @return array> - */ - public function clearCache(array $data): array - { - $episode = (new EpisodeModel())->find( - isset($data['data']) - ? $data['data']['episode_id'] - : $data['id']['episode_id'], - ); - - cache() - ->delete("podcast#{$episode->podcast_id}_episode#{$episode->id}_soundbites"); - - // delete cache for rss feed - cache() - ->deleteMatching("podcast#{$episode->podcast_id}_feed*"); - - cache() - ->deleteMatching("page_podcast#{$episode->podcast_id}_episode#{$episode->id}_*"); - - return $data; - } -} diff --git a/app/Models/StatusModel.php b/app/Models/StatusModel.php deleted file mode 100644 index 132c48ef..00000000 --- a/app/Models/StatusModel.php +++ /dev/null @@ -1,74 +0,0 @@ -where([ - 'episode_id' => $episodeId, - ]) - ->where('`published_at` <= NOW()', null, false) - ->orderBy('published_at', 'DESC') - ->findAll(); - } - - /** - * Retrieves all published statuses for a given episode ordered by publication date - * - * @return Status[] - */ - public function getEpisodeComments(int $episodeId): array - { - return $this->whereIn('in_reply_to_id', function (BaseBuilder $builder) use (&$episodeId): BaseBuilder { - return $builder->select('id') - ->from('activitypub_statuses') - ->where('episode_id', $episodeId); - }) - ->where('`published_at` <= NOW()', null, false) - ->orderBy('published_at', 'ASC') - ->findAll(); - } -} diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php deleted file mode 100644 index 63e90f98..00000000 --- a/app/Models/UserModel.php +++ /dev/null @@ -1,54 +0,0 @@ -select('users.*, auth_groups.name as podcast_role') - ->join('podcasts_users', 'podcasts_users.user_id = users.id') - ->join('auth_groups', 'auth_groups.id = podcasts_users.group_id') - ->where('podcasts_users.podcast_id', $podcastId) - ->findAll(); - - cache() - ->save($cacheName, $found, DECADE); - } - - return $found; - } - - public function getPodcastContributor(int $userId, int $podcastId): ?User - { - return $this->select('users.*, podcasts_users.podcast_id as podcast_id, auth_groups.name as podcast_role') - ->join('podcasts_users', 'podcasts_users.user_id = users.id') - ->join('auth_groups', 'auth_groups.id = podcasts_users.group_id') - ->where([ - 'users.id' => $userId, - 'podcast_id' => $podcastId, - ]) - ->first(); - } -} diff --git a/app/Resources/fonts/montserrat-600.woff2 b/app/Resources/fonts/montserrat-600.woff2 deleted file mode 100644 index 29cc1a97..00000000 Binary files a/app/Resources/fonts/montserrat-600.woff2 and /dev/null differ diff --git a/app/Resources/fonts/montserrat-regular.woff2 b/app/Resources/fonts/montserrat-regular.woff2 deleted file mode 100644 index 70788c27..00000000 Binary files a/app/Resources/fonts/montserrat-regular.woff2 and /dev/null differ diff --git a/app/Resources/icons/add-box.svg b/app/Resources/icons/add-box.svg deleted file mode 100755 index 5a6fd80c..00000000 --- a/app/Resources/icons/add-box.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/add.svg b/app/Resources/icons/add.svg deleted file mode 100755 index 8f3f5a20..00000000 --- a/app/Resources/icons/add.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/alert.svg b/app/Resources/icons/alert.svg deleted file mode 100755 index 7dd74af7..00000000 --- a/app/Resources/icons/alert.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/arrow-left.svg b/app/Resources/icons/arrow-left.svg deleted file mode 100644 index d10d02b5..00000000 --- a/app/Resources/icons/arrow-left.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/arrow-right.svg b/app/Resources/icons/arrow-right.svg deleted file mode 100644 index f46779f7..00000000 --- a/app/Resources/icons/arrow-right.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/bookmark.svg b/app/Resources/icons/bookmark.svg deleted file mode 100755 index d3bde5f3..00000000 --- a/app/Resources/icons/bookmark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/caret-down.svg b/app/Resources/icons/caret-down.svg deleted file mode 100644 index e2138c8d..00000000 --- a/app/Resources/icons/caret-down.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/caret-right.svg b/app/Resources/icons/caret-right.svg deleted file mode 100644 index 346cb156..00000000 --- a/app/Resources/icons/caret-right.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/chat.svg b/app/Resources/icons/chat.svg deleted file mode 100755 index 594b1503..00000000 --- a/app/Resources/icons/chat.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/check.svg b/app/Resources/icons/check.svg deleted file mode 100644 index a28368fc..00000000 --- a/app/Resources/icons/check.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/chevron-left.svg b/app/Resources/icons/chevron-left.svg deleted file mode 100644 index 6d82f7ba..00000000 --- a/app/Resources/icons/chevron-left.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/chevron-right.svg b/app/Resources/icons/chevron-right.svg deleted file mode 100644 index f33dff5e..00000000 --- a/app/Resources/icons/chevron-right.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/close.svg b/app/Resources/icons/close.svg deleted file mode 100644 index 0ef4f305..00000000 --- a/app/Resources/icons/close.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/cloud-off.svg b/app/Resources/icons/cloud-off.svg deleted file mode 100755 index 7177145a..00000000 --- a/app/Resources/icons/cloud-off.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/dashboard.svg b/app/Resources/icons/dashboard.svg deleted file mode 100644 index a25c9e47..00000000 --- a/app/Resources/icons/dashboard.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/delete-bin.svg b/app/Resources/icons/delete-bin.svg deleted file mode 100755 index bd1f9b30..00000000 --- a/app/Resources/icons/delete-bin.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/download.svg b/app/Resources/icons/download.svg deleted file mode 100755 index b3ea2a9f..00000000 --- a/app/Resources/icons/download.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/edit.svg b/app/Resources/icons/edit.svg deleted file mode 100755 index d9efb56c..00000000 --- a/app/Resources/icons/edit.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/external-link.svg b/app/Resources/icons/external-link.svg deleted file mode 100755 index 2efc6259..00000000 --- a/app/Resources/icons/external-link.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/eye.svg b/app/Resources/icons/eye.svg deleted file mode 100755 index f14a8b7d..00000000 --- a/app/Resources/icons/eye.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/file-copy.svg b/app/Resources/icons/file-copy.svg deleted file mode 100755 index 0b907436..00000000 --- a/app/Resources/icons/file-copy.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/file.svg b/app/Resources/icons/file.svg deleted file mode 100755 index d10c86cf..00000000 --- a/app/Resources/icons/file.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/folder-user.svg b/app/Resources/icons/folder-user.svg deleted file mode 100755 index 6dcd37c4..00000000 --- a/app/Resources/icons/folder-user.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/funding/gofundme.svg b/app/Resources/icons/funding/gofundme.svg deleted file mode 100755 index 8573eaa3..00000000 --- a/app/Resources/icons/funding/gofundme.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/helloasso.svg b/app/Resources/icons/funding/helloasso.svg deleted file mode 100755 index a16faf73..00000000 --- a/app/Resources/icons/funding/helloasso.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/indiegogo.svg b/app/Resources/icons/funding/indiegogo.svg deleted file mode 100755 index 0d6240d3..00000000 --- a/app/Resources/icons/funding/indiegogo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/kickstarter.svg b/app/Resources/icons/funding/kickstarter.svg deleted file mode 100755 index 2f055f75..00000000 --- a/app/Resources/icons/funding/kickstarter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/kisskissbankbank.svg b/app/Resources/icons/funding/kisskissbankbank.svg deleted file mode 100755 index f3041450..00000000 --- a/app/Resources/icons/funding/kisskissbankbank.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/liberapay.svg b/app/Resources/icons/funding/liberapay.svg deleted file mode 100755 index e3e261bc..00000000 --- a/app/Resources/icons/funding/liberapay.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/patreon.svg b/app/Resources/icons/funding/patreon.svg deleted file mode 100755 index 0c02798f..00000000 --- a/app/Resources/icons/funding/patreon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/paypal.svg b/app/Resources/icons/funding/paypal.svg deleted file mode 100755 index 5e055a78..00000000 --- a/app/Resources/icons/funding/paypal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/tipeee.svg b/app/Resources/icons/funding/tipeee.svg deleted file mode 100755 index 2984b9b3..00000000 --- a/app/Resources/icons/funding/tipeee.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/funding/ulule.svg b/app/Resources/icons/funding/ulule.svg deleted file mode 100755 index c4231b3e..00000000 --- a/app/Resources/icons/funding/ulule.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/group.svg b/app/Resources/icons/group.svg deleted file mode 100755 index 5c2f10ee..00000000 --- a/app/Resources/icons/group.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/heart.svg b/app/Resources/icons/heart.svg deleted file mode 100755 index f10aafa4..00000000 --- a/app/Resources/icons/heart.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/line-chart.svg b/app/Resources/icons/line-chart.svg deleted file mode 100755 index dc43cd7d..00000000 --- a/app/Resources/icons/line-chart.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/link.svg b/app/Resources/icons/link.svg deleted file mode 100755 index 3b7c8e06..00000000 --- a/app/Resources/icons/link.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/map-pin.svg b/app/Resources/icons/map-pin.svg deleted file mode 100644 index 5950f056..00000000 --- a/app/Resources/icons/map-pin.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/menu.svg b/app/Resources/icons/menu.svg deleted file mode 100755 index 666764dc..00000000 --- a/app/Resources/icons/menu.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/mic.svg b/app/Resources/icons/mic.svg deleted file mode 100755 index becff50c..00000000 --- a/app/Resources/icons/mic.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/more.svg b/app/Resources/icons/more.svg deleted file mode 100755 index 5f6b5dba..00000000 --- a/app/Resources/icons/more.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/movie.svg b/app/Resources/icons/movie.svg deleted file mode 100755 index f92dd60f..00000000 --- a/app/Resources/icons/movie.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/pages.svg b/app/Resources/icons/pages.svg deleted file mode 100755 index 3d28c400..00000000 --- a/app/Resources/icons/pages.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/play.svg b/app/Resources/icons/play.svg deleted file mode 100644 index 4978d3d5..00000000 --- a/app/Resources/icons/play.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/amazon.svg b/app/Resources/icons/podcasting/amazon.svg deleted file mode 100755 index 82ba8b79..00000000 --- a/app/Resources/icons/podcasting/amazon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/antennapod.svg b/app/Resources/icons/podcasting/antennapod.svg deleted file mode 100755 index 26e9699d..00000000 --- a/app/Resources/icons/podcasting/antennapod.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/anytime.svg b/app/Resources/icons/podcasting/anytime.svg deleted file mode 100644 index cfa23d33..00000000 --- a/app/Resources/icons/podcasting/anytime.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/apple.svg b/app/Resources/icons/podcasting/apple.svg deleted file mode 100755 index 358ce6f5..00000000 --- a/app/Resources/icons/podcasting/apple.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/blubrry.svg b/app/Resources/icons/podcasting/blubrry.svg deleted file mode 100755 index d3db4e25..00000000 --- a/app/Resources/icons/podcasting/blubrry.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/breaker.svg b/app/Resources/icons/podcasting/breaker.svg deleted file mode 100755 index 98fe46f3..00000000 --- a/app/Resources/icons/podcasting/breaker.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/breez.svg b/app/Resources/icons/podcasting/breez.svg deleted file mode 100644 index 9dbf46bd..00000000 --- a/app/Resources/icons/podcasting/breez.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/podcasting/castamatic.svg b/app/Resources/icons/podcasting/castamatic.svg deleted file mode 100644 index 8fb53cfc..00000000 --- a/app/Resources/icons/podcasting/castamatic.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/castbox.svg b/app/Resources/icons/podcasting/castbox.svg deleted file mode 100755 index f3b4a197..00000000 --- a/app/Resources/icons/podcasting/castbox.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/castcoverage.svg b/app/Resources/icons/podcasting/castcoverage.svg deleted file mode 100644 index 37db9e3d..00000000 --- a/app/Resources/icons/podcasting/castcoverage.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/castopod.svg b/app/Resources/icons/podcasting/castopod.svg deleted file mode 100755 index ff91790c..00000000 --- a/app/Resources/icons/podcasting/castopod.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/castro.svg b/app/Resources/icons/podcasting/castro.svg deleted file mode 100755 index d3716c8e..00000000 --- a/app/Resources/icons/podcasting/castro.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/chartable.svg b/app/Resources/icons/podcasting/chartable.svg deleted file mode 100755 index 6383bbfc..00000000 --- a/app/Resources/icons/podcasting/chartable.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/curiocaster.svg b/app/Resources/icons/podcasting/curiocaster.svg deleted file mode 100644 index 2d61da69..00000000 --- a/app/Resources/icons/podcasting/curiocaster.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/deezer.svg b/app/Resources/icons/podcasting/deezer.svg deleted file mode 100755 index 869b06ef..00000000 --- a/app/Resources/icons/podcasting/deezer.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/escapepod.svg b/app/Resources/icons/podcasting/escapepod.svg deleted file mode 100644 index 3c652c94..00000000 --- a/app/Resources/icons/podcasting/escapepod.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/fountain.svg b/app/Resources/icons/podcasting/fountain.svg deleted file mode 100644 index 87d3b096..00000000 --- a/app/Resources/icons/podcasting/fountain.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/fyyd.svg b/app/Resources/icons/podcasting/fyyd.svg deleted file mode 100755 index f8b6518c..00000000 --- a/app/Resources/icons/podcasting/fyyd.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/google.svg b/app/Resources/icons/podcasting/google.svg deleted file mode 100755 index 51056db8..00000000 --- a/app/Resources/icons/podcasting/google.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/gpodder.svg b/app/Resources/icons/podcasting/gpodder.svg deleted file mode 100644 index 1acbdc9c..00000000 --- a/app/Resources/icons/podcasting/gpodder.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/podcasting/hypercatcher.svg b/app/Resources/icons/podcasting/hypercatcher.svg deleted file mode 100644 index 9131519f..00000000 --- a/app/Resources/icons/podcasting/hypercatcher.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/ivoox.svg b/app/Resources/icons/podcasting/ivoox.svg deleted file mode 100755 index 6715e452..00000000 --- a/app/Resources/icons/podcasting/ivoox.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/ivyfm.svg b/app/Resources/icons/podcasting/ivyfm.svg deleted file mode 100644 index 70475f98..00000000 --- a/app/Resources/icons/podcasting/ivyfm.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/jumplink.svg b/app/Resources/icons/podcasting/jumplink.svg deleted file mode 100644 index e5dc38f4..00000000 --- a/app/Resources/icons/podcasting/jumplink.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/kasts.svg b/app/Resources/icons/podcasting/kasts.svg deleted file mode 100644 index af8e6b0a..00000000 --- a/app/Resources/icons/podcasting/kasts.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/podcasting/listennotes.svg b/app/Resources/icons/podcasting/listennotes.svg deleted file mode 100755 index 05f99886..00000000 --- a/app/Resources/icons/podcasting/listennotes.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/overcast.svg b/app/Resources/icons/podcasting/overcast.svg deleted file mode 100755 index 74252263..00000000 --- a/app/Resources/icons/podcasting/overcast.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/playapod.svg b/app/Resources/icons/podcasting/playapod.svg deleted file mode 100644 index c06ebb1a..00000000 --- a/app/Resources/icons/podcasting/playapod.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/playerfm.svg b/app/Resources/icons/podcasting/playerfm.svg deleted file mode 100755 index fc24e26d..00000000 --- a/app/Resources/icons/podcasting/playerfm.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/plink.svg b/app/Resources/icons/podcasting/plink.svg deleted file mode 100644 index ef7781d8..00000000 --- a/app/Resources/icons/podcasting/plink.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/podcasting/pocketcasts.svg b/app/Resources/icons/podcasting/pocketcasts.svg deleted file mode 100755 index bb551312..00000000 --- a/app/Resources/icons/podcasting/pocketcasts.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podbean.svg b/app/Resources/icons/podcasting/podbean.svg deleted file mode 100755 index c8577b5f..00000000 --- a/app/Resources/icons/podcasting/podbean.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podcastaddict.svg b/app/Resources/icons/podcasting/podcastaddict.svg deleted file mode 100755 index 2db58457..00000000 --- a/app/Resources/icons/podcasting/podcastaddict.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podcastchapters.svg b/app/Resources/icons/podcasting/podcastchapters.svg deleted file mode 100644 index 6d06725c..00000000 --- a/app/Resources/icons/podcasting/podcastchapters.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/podcasting/podcastguru.svg b/app/Resources/icons/podcasting/podcastguru.svg deleted file mode 100644 index 3d1e1e1e..00000000 --- a/app/Resources/icons/podcasting/podcastguru.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/podcastindex.svg b/app/Resources/icons/podcasting/podcastindex.svg deleted file mode 100755 index 4b88645e..00000000 --- a/app/Resources/icons/podcasting/podcastindex.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podchaser.svg b/app/Resources/icons/podcasting/podchaser.svg deleted file mode 100755 index ca80217d..00000000 --- a/app/Resources/icons/podcasting/podchaser.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podcloud.svg b/app/Resources/icons/podcasting/podcloud.svg deleted file mode 100755 index 9abda5d7..00000000 --- a/app/Resources/icons/podcasting/podcloud.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podfriend.svg b/app/Resources/icons/podcasting/podfriend.svg deleted file mode 100755 index 6c96c60d..00000000 --- a/app/Resources/icons/podcasting/podfriend.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podinstall.svg b/app/Resources/icons/podcasting/podinstall.svg deleted file mode 100755 index 9bec6ac6..00000000 --- a/app/Resources/icons/podcasting/podinstall.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podlink.svg b/app/Resources/icons/podcasting/podlink.svg deleted file mode 100755 index c980f8f6..00000000 --- a/app/Resources/icons/podcasting/podlink.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podlp.svg b/app/Resources/icons/podcasting/podlp.svg deleted file mode 100644 index 4ea74517..00000000 --- a/app/Resources/icons/podcasting/podlp.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/podnews.svg b/app/Resources/icons/podcasting/podnews.svg deleted file mode 100644 index 786e65f0..00000000 --- a/app/Resources/icons/podcasting/podnews.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/podcasting/podstation.svg b/app/Resources/icons/podcasting/podstation.svg deleted file mode 100644 index 2e1a9660..00000000 --- a/app/Resources/icons/podcasting/podstation.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/podtail.svg b/app/Resources/icons/podcasting/podtail.svg deleted file mode 100755 index 09426777..00000000 --- a/app/Resources/icons/podcasting/podtail.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/podverse.svg b/app/Resources/icons/podcasting/podverse.svg deleted file mode 100755 index ccec56af..00000000 --- a/app/Resources/icons/podcasting/podverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/radiopublic.svg b/app/Resources/icons/podcasting/radiopublic.svg deleted file mode 100755 index 1803cccd..00000000 --- a/app/Resources/icons/podcasting/radiopublic.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/sphinxchat.svg b/app/Resources/icons/podcasting/sphinxchat.svg deleted file mode 100644 index f27b0e48..00000000 --- a/app/Resources/icons/podcasting/sphinxchat.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/spotify.svg b/app/Resources/icons/podcasting/spotify.svg deleted file mode 100755 index da84da85..00000000 --- a/app/Resources/icons/podcasting/spotify.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/spreaker.svg b/app/Resources/icons/podcasting/spreaker.svg deleted file mode 100755 index 06ddebe3..00000000 --- a/app/Resources/icons/podcasting/spreaker.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/stitcher.svg b/app/Resources/icons/podcasting/stitcher.svg deleted file mode 100755 index b2f7c0d0..00000000 --- a/app/Resources/icons/podcasting/stitcher.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/tsacdop.svg b/app/Resources/icons/podcasting/tsacdop.svg deleted file mode 100644 index e5459ffb..00000000 --- a/app/Resources/icons/podcasting/tsacdop.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/Resources/icons/podcasting/tunein.svg b/app/Resources/icons/podcasting/tunein.svg deleted file mode 100755 index 8ebef8d4..00000000 --- a/app/Resources/icons/podcasting/tunein.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/podcasting/zion.svg b/app/Resources/icons/podcasting/zion.svg deleted file mode 100644 index b2650bac..00000000 --- a/app/Resources/icons/podcasting/zion.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/Resources/icons/question.svg b/app/Resources/icons/question.svg deleted file mode 100755 index b7fd91ed..00000000 --- a/app/Resources/icons/question.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/repeat.svg b/app/Resources/icons/repeat.svg deleted file mode 100644 index c5a26047..00000000 --- a/app/Resources/icons/repeat.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/rss.svg b/app/Resources/icons/rss.svg deleted file mode 100755 index 723552d9..00000000 --- a/app/Resources/icons/rss.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/scales.svg b/app/Resources/icons/scales.svg deleted file mode 100755 index 7383e06a..00000000 --- a/app/Resources/icons/scales.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/settings.svg b/app/Resources/icons/settings.svg deleted file mode 100755 index 893c92d2..00000000 --- a/app/Resources/icons/settings.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/social/castopod.svg b/app/Resources/icons/social/castopod.svg deleted file mode 100755 index ff91790c..00000000 --- a/app/Resources/icons/social/castopod.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/discord.svg b/app/Resources/icons/social/discord.svg deleted file mode 100755 index ad22eebd..00000000 --- a/app/Resources/icons/social/discord.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/facebook.svg b/app/Resources/icons/social/facebook.svg deleted file mode 100755 index 4d215877..00000000 --- a/app/Resources/icons/social/facebook.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/funkwhale.svg b/app/Resources/icons/social/funkwhale.svg deleted file mode 100755 index 4abbeaad..00000000 --- a/app/Resources/icons/social/funkwhale.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/instagram.svg b/app/Resources/icons/social/instagram.svg deleted file mode 100755 index a56bb3e9..00000000 --- a/app/Resources/icons/social/instagram.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/linkedin.svg b/app/Resources/icons/social/linkedin.svg deleted file mode 100755 index 78000a7a..00000000 --- a/app/Resources/icons/social/linkedin.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/mastodon.svg b/app/Resources/icons/social/mastodon.svg deleted file mode 100755 index f9315563..00000000 --- a/app/Resources/icons/social/mastodon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/mobilizon.svg b/app/Resources/icons/social/mobilizon.svg deleted file mode 100755 index b7fd11a6..00000000 --- a/app/Resources/icons/social/mobilizon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/peertube.svg b/app/Resources/icons/social/peertube.svg deleted file mode 100755 index 0fb16946..00000000 --- a/app/Resources/icons/social/peertube.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/pixelfed.svg b/app/Resources/icons/social/pixelfed.svg deleted file mode 100755 index b3471340..00000000 --- a/app/Resources/icons/social/pixelfed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/plume.svg b/app/Resources/icons/social/plume.svg deleted file mode 100755 index a1009fa5..00000000 --- a/app/Resources/icons/social/plume.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/reddit.svg b/app/Resources/icons/social/reddit.svg deleted file mode 100755 index a97eb3e2..00000000 --- a/app/Resources/icons/social/reddit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/slack.svg b/app/Resources/icons/social/slack.svg deleted file mode 100755 index 03fa2ede..00000000 --- a/app/Resources/icons/social/slack.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/tiktok.svg b/app/Resources/icons/social/tiktok.svg deleted file mode 100755 index 0362bd93..00000000 --- a/app/Resources/icons/social/tiktok.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/twitch.svg b/app/Resources/icons/social/twitch.svg deleted file mode 100755 index dbc56ddc..00000000 --- a/app/Resources/icons/social/twitch.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/twitter.svg b/app/Resources/icons/social/twitter.svg deleted file mode 100755 index c32aa097..00000000 --- a/app/Resources/icons/social/twitter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/writefreely.svg b/app/Resources/icons/social/writefreely.svg deleted file mode 100755 index e6a02e09..00000000 --- a/app/Resources/icons/social/writefreely.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/social/youtube.svg b/app/Resources/icons/social/youtube.svg deleted file mode 100755 index dca4bf6f..00000000 --- a/app/Resources/icons/social/youtube.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/Resources/icons/star-smile.svg b/app/Resources/icons/star-smile.svg deleted file mode 100755 index 05014c31..00000000 --- a/app/Resources/icons/star-smile.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/timer.svg b/app/Resources/icons/timer.svg deleted file mode 100755 index 21ab4767..00000000 --- a/app/Resources/icons/timer.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/upload-cloud.svg b/app/Resources/icons/upload-cloud.svg deleted file mode 100755 index b87c7581..00000000 --- a/app/Resources/icons/upload-cloud.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/user-add.svg b/app/Resources/icons/user-add.svg deleted file mode 100755 index 2d56227f..00000000 --- a/app/Resources/icons/user-add.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/icons/user.svg b/app/Resources/icons/user.svg deleted file mode 100755 index f6566c8e..00000000 --- a/app/Resources/icons/user.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/Resources/images/castopod-avatar-default.jpg b/app/Resources/images/castopod-avatar-default.jpg deleted file mode 100644 index 644126c5..00000000 Binary files a/app/Resources/images/castopod-avatar-default.jpg and /dev/null differ diff --git a/app/Resources/images/castopod-cover-default.jpg b/app/Resources/images/castopod-cover-default.jpg deleted file mode 100644 index 9fe87fd6..00000000 Binary files a/app/Resources/images/castopod-cover-default.jpg and /dev/null differ diff --git a/app/Resources/images/castopod-logo.svg b/app/Resources/images/castopod-logo.svg deleted file mode 100644 index 444036e3..00000000 --- a/app/Resources/images/castopod-logo.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/Resources/images/castopod-mascot_confused.svg b/app/Resources/images/castopod-mascot_confused.svg deleted file mode 100644 index b4ff04f5..00000000 --- a/app/Resources/images/castopod-mascot_confused.svg +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/Resources/js/admin.ts b/app/Resources/js/admin.ts deleted file mode 100644 index 2580f6d5..00000000 --- a/app/Resources/js/admin.ts +++ /dev/null @@ -1,27 +0,0 @@ -import ClientTimezone from "./modules/ClientTimezone"; -import Clipboard from "./modules/Clipboard"; -import DateTimePicker from "./modules/DateTimePicker"; -import Dropdown from "./modules/Dropdown"; -import MarkdownEditor from "./modules/MarkdownEditor"; -import MultiSelect from "./modules/MultiSelect"; -import PublishMessageWarning from "./modules/PublishMessageWarning"; -import SidebarToggler from "./modules/SidebarToggler"; -import Slugify from "./modules/Slugify"; -import Soundbites from "./modules/Soundbites"; -import ThemePicker from "./modules/ThemePicker"; -import Time from "./modules/Time"; -import Tooltip from "./modules/Tooltip"; - -Dropdown(); -Tooltip(); -MarkdownEditor(); -MultiSelect(); -Slugify(); -SidebarToggler(); -ClientTimezone(); -DateTimePicker(); -Time(); -Soundbites(); -Clipboard(); -ThemePicker(); -PublishMessageWarning(); diff --git a/app/Resources/js/charts.ts b/app/Resources/js/charts.ts deleted file mode 100644 index de52bd13..00000000 --- a/app/Resources/js/charts.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "core-js"; -import DrawCharts from "./modules/Charts"; - -DrawCharts(); diff --git a/app/Resources/js/favicon.svg b/app/Resources/js/favicon.svg deleted file mode 100644 index de4aeddc..00000000 --- a/app/Resources/js/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/app/Resources/js/install.ts b/app/Resources/js/install.ts deleted file mode 100644 index e3bb9d53..00000000 --- a/app/Resources/js/install.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Tooltip from "./modules/Tooltip"; - -Tooltip(); diff --git a/app/Resources/js/map.ts b/app/Resources/js/map.ts deleted file mode 100644 index 66afdef9..00000000 --- a/app/Resources/js/map.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "core-js"; -import DrawEpisodesMaps from "./modules/EpisodesMap"; - -DrawEpisodesMaps(); diff --git a/app/Resources/js/modules/Clipboard.ts b/app/Resources/js/modules/Clipboard.ts deleted file mode 100644 index 7b4e4ebf..00000000 --- a/app/Resources/js/modules/Clipboard.ts +++ /dev/null @@ -1,23 +0,0 @@ -const Clipboard = (): void => { - const buttons: NodeListOf | null = document.querySelectorAll( - "button[data-type='clipboard-copy']" - ); - - if (buttons) { - for (let i = 0; i < buttons.length; i++) { - const button: HTMLButtonElement = buttons[i]; - const textArea: HTMLTextAreaElement | null = document.querySelector( - `textarea[id="${button.dataset.clipboardTarget}"]` - ); - if (textArea) { - button.addEventListener("click", () => { - textArea.select(); - textArea.setSelectionRange(0, textArea.value.length); - document.execCommand("copy"); - }); - } - } - } -}; - -export default Clipboard; diff --git a/app/Resources/js/modules/Dropdown.ts b/app/Resources/js/modules/Dropdown.ts deleted file mode 100644 index 231e028f..00000000 --- a/app/Resources/js/modules/Dropdown.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { createPopper, Instance, Placement } from "@popperjs/core"; - -const Dropdown = (): void => { - const dropdownButtons: NodeListOf = document.querySelectorAll( - "[data-dropdown='button']" - ); - - for (let i = 0; i < dropdownButtons.length; i++) { - const button = dropdownButtons[i]; - - if (button.dataset.dropdownTarget) { - const menu: HTMLElement | null = document.getElementById( - button.dataset?.dropdownTarget - ); - - if (menu) { - // place the menu at then end of the body to prevent any overflow cuts - document.body.appendChild(menu); - - let popperInstance: Instance | null = null; - - const create = () => { - const offsetX = menu.dataset.dropdownOffsetX - ? parseInt(menu.dataset.dropdownOffsetX) - : 0; - const offsetY = menu.dataset.dropdownOffsetY - ? parseInt(menu.dataset.dropdownOffsetY) - : 0; - popperInstance = createPopper(button, menu, { - placement: menu.dataset.dropdownPlacement as Placement, - // strategy: "fixed", - modifiers: [ - { - name: "offset", - options: { - offset: [offsetX, offsetY], - }, - }, - ], - }); - }; - - const destroy = () => { - if (popperInstance) { - popperInstance.destroy(); - popperInstance = null; - } - }; - - const dropdownToggle = () => { - const isExpanded = menu.hasAttribute("data-show"); - - if (isExpanded) { - menu.removeAttribute("data-show"); - button.setAttribute("aria-expanded", "false"); - destroy(); - } else { - menu.setAttribute("data-show", ""); - button.setAttribute("aria-expanded", "true"); - create(); - } - }; - - // Toggle dropdown menu on button click event - button.addEventListener("click", dropdownToggle); - - // Toggle off when clicking outside of dropdown - document.addEventListener("click", function (event) { - const isExpanded = menu.hasAttribute("data-show"); - const isClickOutside = - !menu.contains(event.target as Node) && - !button.contains(event.target as Node); - - if (isExpanded && isClickOutside) { - dropdownToggle(); - } - }); - } - } - } -}; - -export default Dropdown; diff --git a/app/Resources/js/modules/MarkdownEditor.ts b/app/Resources/js/modules/MarkdownEditor.ts deleted file mode 100644 index 07dfe266..00000000 --- a/app/Resources/js/modules/MarkdownEditor.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { exampleSetup } from "prosemirror-example-setup"; -import "prosemirror-example-setup/style/style.css"; -import { - defaultMarkdownParser, - defaultMarkdownSerializer, - schema, -} from "prosemirror-markdown"; -import "prosemirror-menu/style/menu.css"; -import { EditorState } from "prosemirror-state"; -import { EditorView } from "prosemirror-view"; -import "prosemirror-view/style/prosemirror.css"; - -class MarkdownView { - textarea: HTMLTextAreaElement; - - constructor(target: HTMLTextAreaElement) { - this.textarea = target; - this.textarea.classList.add("w-full", "h-full"); - } - - content() { - return this.textarea.innerHTML; - } - focus() { - this.textarea.focus(); - } - show() { - this.textarea.classList.remove("hidden"); - } - hide() { - this.textarea.classList.add("hidden"); - } -} - -class ProseMirrorView { - editorContainer: HTMLDivElement; - view: EditorView; - - constructor(target: HTMLTextAreaElement, content: string) { - this.editorContainer = document.createElement("div"); - this.editorContainer.classList.add("bg-white", "border"); - this.editorContainer.style.minHeight = "200px"; - const editor = target.parentNode?.insertBefore( - this.editorContainer, - target.nextSibling - ); - - this.view = new EditorView(editor, { - state: EditorState.create({ - doc: defaultMarkdownParser.parse(content), - plugins: exampleSetup({ schema }), - }), - dispatchTransaction: (transaction) => { - const newState = this.view.state.apply(transaction); - this.view.updateState(newState); - - if (transaction.docChanged) { - target.innerHTML = this.content(); - } - }, - attributes: { - class: "prose-sm px-3 py-2 overflow-y-auto focus:ring", - style: "min-height: 200px; max-height: 500px", - }, - }); - } - - content(): string { - return defaultMarkdownSerializer.serialize(this.view.state.doc) || ""; - } - focus() { - this.view.focus(); - } - show() { - this.editorContainer.classList.remove("hidden"); - } - hide() { - this.editorContainer.classList.add("hidden"); - } -} - -const MarkdownEditor = (): void => { - const targets: NodeListOf = document.querySelectorAll( - "textarea[data-editor='markdown']" - ); - const activeClass = "font-semibold"; - - for (let i = 0; i < targets.length; i++) { - const target = targets[i]; - - const wysiwygBtn = document.createElement("button"); - wysiwygBtn.classList.add( - activeClass, - "py-1", - "px-2", - "bg-white", - "border", - "text-xs", - "outline-none", - "focus:ring" - ); - wysiwygBtn.setAttribute("type", "button"); - wysiwygBtn.innerHTML = "Wysiwyg"; - const markdownBtn = document.createElement("button"); - markdownBtn.classList.add( - "py-1", - "px-2", - "bg-white", - "border", - "text-xs", - "outline-none", - "focus:ring" - ); - markdownBtn.setAttribute("type", "button"); - markdownBtn.innerHTML = "Markdown"; - - const viewButtons = document.createElement("div"); - viewButtons.appendChild(wysiwygBtn); - viewButtons.appendChild(markdownBtn); - viewButtons.classList.add( - "inline-flex", - "absolute", - "top-0", - "right-0", - "-mt-6" - ); - - const markdownEditorContainer = document.createElement("div"); - markdownEditorContainer.classList.add("relative"); - markdownEditorContainer.style.minHeight = "200px"; - target.parentNode?.appendChild(markdownEditorContainer); - markdownEditorContainer.appendChild(target); - - // show WYSIWYG editor by default - target.classList.add("hidden"); - const markdownView = new MarkdownView(target); - const wysiwygView = new ProseMirrorView(target, markdownView.content()); - - markdownEditorContainer.appendChild(viewButtons); - - markdownBtn.addEventListener("click", () => { - if (markdownBtn.classList.contains(activeClass)) return; - markdownBtn.classList.add(activeClass); - wysiwygBtn.classList.remove(activeClass); - wysiwygView.hide(); - markdownView.show(); - }); - - wysiwygBtn.addEventListener("click", () => { - if (wysiwygBtn.classList.contains(activeClass)) return; - wysiwygBtn.classList.add(activeClass); - markdownBtn.classList.remove(activeClass); - markdownView.hide(); - wysiwygView.show(); - }); - } -}; - -export default MarkdownEditor; diff --git a/app/Resources/js/modules/Modal.ts b/app/Resources/js/modules/Modal.ts deleted file mode 100644 index 060540a0..00000000 --- a/app/Resources/js/modules/Modal.ts +++ /dev/null @@ -1,34 +0,0 @@ -const Modal = (): void => { - const modalTriggerElements: NodeListOf = document.querySelectorAll( - "[data-modal-target]" - ); - - for (let i = 0; i < modalTriggerElements.length; i++) { - const modalTrigger = modalTriggerElements[i]; - - if (modalTrigger.dataset.modalTarget) { - const modal: HTMLElement | null = document.getElementById( - modalTrigger.dataset.modalTarget - ); - - if (modal) { - modalTrigger.addEventListener("click", () => { - modal.classList.toggle("hidden"); - }); - - const closeButtonsElements: NodeListOf = modal.querySelectorAll( - "[data-modal-button]" - ); - - for (let j = 0; j < closeButtonsElements.length; j++) { - const closeButton = closeButtonsElements[j]; - closeButton.addEventListener("click", () => { - modal.classList.toggle("hidden"); - }); - } - } - } - } -}; - -export default Modal; diff --git a/app/Resources/js/modules/MultiSelect.ts b/app/Resources/js/modules/MultiSelect.ts deleted file mode 100644 index 9268b76f..00000000 --- a/app/Resources/js/modules/MultiSelect.ts +++ /dev/null @@ -1,51 +0,0 @@ -import Choices from "choices.js"; - -const MultiSelect = (): void => { - // Pass single element - const multiSelects: NodeListOf = document.querySelectorAll( - "select[multiple]" - ); - - for (let i = 0; i < multiSelects.length; i++) { - const multiSelect = multiSelects[i]; - - new Choices(multiSelect, { - maxItemCount: parseInt(multiSelect.dataset.maxItemCount || "-1"), - itemSelectText: multiSelect.dataset.selectText, - maxItemText: multiSelect.dataset.maxItemText, - removeItemButton: true, - classNames: { - containerOuter: - "multiselect" + - (multiSelect.dataset.class ? ` ${multiSelect.dataset.class}` : ""), - containerInner: "multiselect__inner", - input: "multiselect__input", - inputCloned: "multiselect__input--cloned", - list: "multiselect__list", - listItems: "multiselect__list--multiple", - listSingle: "multiselect__list--single", - listDropdown: "multiselect__list--dropdown", - item: "multiselect__item", - itemSelectable: "multiselect__item--selectable", - itemDisabled: "multiselect__item--disabled", - itemChoice: "multiselect__item--choice", - placeholder: "multiselect__placeholder", - group: "multiselect__group", - groupHeading: "multiselect__heading", - button: "multiselect__button", - activeState: "is-active", - focusState: "is-focused", - openState: "is-open", - disabledState: "is-disabled", - highlightedState: "is-highlighted", - selectedState: "is-selected", - flippedState: "is-flipped", - loadingState: "is-loading", - noResults: "has-no-results", - noChoices: "has-no-choices", - }, - }); - } -}; - -export default MultiSelect; diff --git a/app/Resources/js/modules/SidebarToggler.ts b/app/Resources/js/modules/SidebarToggler.ts deleted file mode 100644 index f9176f4f..00000000 --- a/app/Resources/js/modules/SidebarToggler.ts +++ /dev/null @@ -1,62 +0,0 @@ -const SidebarToggler = (): void => { - const sidebar = document.querySelector( - "aside[id='admin-sidebar']" - ) as HTMLElement; - const toggler = document.querySelector( - "button[id='sidebar-toggler']" - ) as HTMLButtonElement; - const sidebarBackdrop = document.querySelector( - "div[id='sidebar-backdrop']" - ) as HTMLElement; - - const setAriaExpanded = (isExpanded: "true" | "false") => { - toggler.setAttribute("aria-expanded", isExpanded); - sidebarBackdrop.setAttribute("aria-expanded", isExpanded); - }; - - const hideSidebar = () => { - setAriaExpanded("false"); - sidebar.classList.add("-translate-x-full"); - sidebarBackdrop.classList.add("hidden"); - toggler.style.transform = "translateX(0px)"; - }; - - const showSidebar = () => { - setAriaExpanded("true"); - sidebar.classList.remove("-translate-x-full"); - sidebarBackdrop.classList.remove("hidden"); - toggler.style.transform = - "translateX(" + sidebar.getBoundingClientRect().width + "px)"; - }; - - toggler.addEventListener("click", () => { - if (sidebar.classList.contains("-translate-x-full")) { - showSidebar(); - } else { - hideSidebar(); - } - }); - - sidebarBackdrop.addEventListener("click", () => { - if (!sidebar.classList.contains("-translate-x-full")) { - hideSidebar(); - } - }); - - const setAriaExpandedOnWindowEvent = () => { - const isExpanded = - !sidebar.classList.contains("-translate-x-full") || - window.innerWidth >= 768; - const ariaExpanded = toggler.getAttribute("aria-expanded"); - if (isExpanded && (!ariaExpanded || ariaExpanded === "false")) { - setAriaExpanded("true"); - } else if (!isExpanded && (!ariaExpanded || ariaExpanded === "true")) { - setAriaExpanded("false"); - } - }; - - window.addEventListener("load", setAriaExpandedOnWindowEvent); - window.addEventListener("resize", setAriaExpandedOnWindowEvent); -}; - -export default SidebarToggler; diff --git a/app/Resources/js/modules/Soundbites.ts b/app/Resources/js/modules/Soundbites.ts deleted file mode 100644 index 7c2009fa..00000000 --- a/app/Resources/js/modules/Soundbites.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * TODO: refactor file - */ -let timeout: number | null = null; - -const playSoundbite = ( - audioPlayer: HTMLAudioElement, - startTime: number, - duration: number -): void => { - audioPlayer.currentTime = startTime; - if (duration > 0) { - audioPlayer.play(); - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - timeout = window.setTimeout(() => { - audioPlayer.pause(); - timeout = null; - }, duration * 1000); - } -}; - -const Soundbites = (): void => { - const audioPlayer: HTMLAudioElement | null = document.querySelector("audio"); - - if (audioPlayer) { - const soundbiteButton: HTMLButtonElement | null = document.querySelector( - "button[data-type='get-soundbite']" - ); - if (soundbiteButton) { - const startTimeField: HTMLInputElement | null = document.querySelector( - `input[name="${soundbiteButton.dataset.startTimeFieldName}"]` - ); - const durationField: HTMLInputElement | null = document.querySelector( - `input[name="${soundbiteButton.dataset.durationFieldName}"]` - ); - - if (startTimeField && durationField) { - soundbiteButton.addEventListener("click", () => { - if (startTimeField.value === "") { - startTimeField.value = ( - Math.round(audioPlayer.currentTime * 100) / 100 - ).toString(); - } else { - durationField.value = ( - Math.round( - (audioPlayer.currentTime - Number(startTimeField.value)) * 100 - ) / 100 - ).toString(); - } - }); - } - } - - const soundbitePlayButtons: NodeListOf | null = document.querySelectorAll( - "button[data-type='play-soundbite']" - ); - if (soundbitePlayButtons) { - for (let i = 0; i < soundbitePlayButtons.length; i++) { - const soundbitePlayButton: HTMLButtonElement = soundbitePlayButtons[i]; - soundbitePlayButton.addEventListener("click", () => { - playSoundbite( - audioPlayer, - Number(soundbitePlayButton.dataset.soundbiteStartTime), - Number(soundbitePlayButton.dataset.soundbiteDuration) - ); - }); - } - } - - const inputFields: NodeListOf | null = document.querySelectorAll( - "input[data-type='soundbite-field']" - ); - if (inputFields) { - for (let i = 0; i < inputFields.length; i++) { - const inputField: HTMLInputElement = inputFields[i]; - const soundbitePlayButton: HTMLButtonElement | null = document.querySelector( - `button[data-type="play-soundbite"][data-soundbite-id="${inputField.dataset.soundbiteId}"]` - ); - if (soundbitePlayButton) { - if (inputField.dataset.fieldType == "start-time") { - inputField.addEventListener("input", () => { - soundbitePlayButton.dataset.soundbiteStartTime = inputField.value; - }); - } else if (inputField.dataset.fieldType == "duration") { - inputField.addEventListener("input", () => { - soundbitePlayButton.dataset.soundbiteDuration = inputField.value; - }); - } - } - } - } - } -}; - -export default Soundbites; diff --git a/app/Resources/js/modules/ThemePicker.ts b/app/Resources/js/modules/ThemePicker.ts deleted file mode 100644 index d495170c..00000000 --- a/app/Resources/js/modules/ThemePicker.ts +++ /dev/null @@ -1,30 +0,0 @@ -const ThemePicker = (): void => { - const buttons: NodeListOf | null = document.querySelectorAll( - "button[data-type='theme-picker']" - ); - const iframe: HTMLIFrameElement | null = document.querySelector( - `iframe[id="embeddable_player"]` - ); - const iframeTextArea: HTMLTextAreaElement | null = document.querySelector( - `textarea[id="iframe"]` - ); - const urlTextArea: HTMLTextAreaElement | null = document.querySelector( - `textarea[id="url"]` - ); - - if (buttons && iframe && iframeTextArea && urlTextArea) { - for (let i = 0; i < buttons.length; i++) { - const button: HTMLButtonElement = buttons[i]; - const url: string | undefined = button.dataset.url; - if (url) { - button.addEventListener("click", () => { - iframeTextArea.value = ``; - urlTextArea.value = url; - iframe.src = url; - }); - } - } - } -}; - -export default ThemePicker; diff --git a/app/Resources/js/modules/Tooltip.ts b/app/Resources/js/modules/Tooltip.ts deleted file mode 100644 index b8d2ab2d..00000000 --- a/app/Resources/js/modules/Tooltip.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createPopper, Placement } from "@popperjs/core"; - -const Tooltip = (): void => { - const tooltipContainers: NodeListOf = document.querySelectorAll( - "[data-toggle='tooltip']" - ); - - for (let i = 0; i < tooltipContainers.length; i++) { - const tooltipReference = tooltipContainers[i]; - const tooltipContent = tooltipReference.title; - - const tooltip = document.createElement("div"); - tooltip.setAttribute("id", "tooltip" + i); - tooltip.setAttribute( - "class", - "px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50" - ); - tooltip.innerHTML = tooltipContent; - - const popper = createPopper(tooltipReference, tooltip, { - placement: tooltipReference.dataset.placement as Placement, - modifiers: [ - { - name: "offset", - options: { - offset: [0, 8], - }, - }, - ], - }); - - const show = () => { - tooltipReference.removeAttribute("title"); - tooltipReference.setAttribute("aria-describedby", "tooltip" + i); - document.body.appendChild(tooltip); - popper.update(); - }; - - const hide = () => { - const element = document.getElementById("tooltip" + i); - tooltipReference.removeAttribute("aria-describedby"); - tooltipReference.setAttribute("title", tooltipContent); - if (element) { - document.body.removeChild(element); - } - }; - - const showEvents = ["mouseenter", "focus"]; - const hideEvents = ["mouseleave", "blur"]; - - showEvents.forEach((event) => { - tooltipReference.addEventListener(event, show); - }); - - hideEvents.forEach((event) => { - tooltipReference.addEventListener(event, hide); - }); - } -}; - -export default Tooltip; diff --git a/app/Resources/js/podcast.ts b/app/Resources/js/podcast.ts deleted file mode 100644 index 67235fe7..00000000 --- a/app/Resources/js/podcast.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Dropdown from "./modules/Dropdown"; -import Time from "./modules/Time"; -import Toggler from "./modules/Toggler"; -import Tooltip from "./modules/Tooltip"; - -Dropdown(); -Time(); -Toggler(); -Tooltip(); diff --git a/app/Resources/js/typings.d.ts b/app/Resources/js/typings.d.ts deleted file mode 100644 index fe9d4f51..00000000 --- a/app/Resources/js/typings.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare module "prosemirror-markdown"; -declare module "prosemirror-example-setup"; -declare module "leaflet.markercluster"; diff --git a/app/Resources/js/vite-env.d.ts b/app/Resources/js/vite-env.d.ts deleted file mode 100644 index 11f02fe2..00000000 --- a/app/Resources/js/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/app/Resources/styles/breadcrumb.css b/app/Resources/styles/breadcrumb.css deleted file mode 100644 index 0a89fe55..00000000 --- a/app/Resources/styles/breadcrumb.css +++ /dev/null @@ -1,20 +0,0 @@ -.breadcrumb { - @apply inline-flex flex-wrap px-1 py-2 text-sm; -} - -.breadcrumb-item + .breadcrumb-item::before { - @apply inline-block px-1 text-gray-500; - content: "/"; -} - -.breadcrumb-item a { - @apply no-underline; - - &:hover { - @apply underline; - } -} - -.breadcrumb-item.active { - @apply font-semibold; -} diff --git a/app/Resources/styles/charts.css b/app/Resources/styles/charts.css deleted file mode 100644 index b1bb0294..00000000 --- a/app/Resources/styles/charts.css +++ /dev/null @@ -1,15 +0,0 @@ -.chart-map { - height: 600px; - border: solid 10px #eee; -} -.chart-pie { - height: 450px; - width: 100%; - border: solid 1px #eee; -} -.chart-xy { - height: 500px; - width: 100%; - border: solid 1px #eee; - border: solid 3px #eee; -} diff --git a/app/Resources/styles/dropdown.css b/app/Resources/styles/dropdown.css deleted file mode 100644 index bf3e2ed0..00000000 --- a/app/Resources/styles/dropdown.css +++ /dev/null @@ -1,8 +0,0 @@ -@layer base { - [data-dropdown="menu"] { - @apply z-50; - } - [data-dropdown="menu"]:not([data-show]) { - @apply absolute top-0 left-0 invisible pointer-events-none; - } -} diff --git a/app/Resources/styles/fonts.css b/app/Resources/styles/fonts.css deleted file mode 100644 index 3e92e823..00000000 --- a/app/Resources/styles/fonts.css +++ /dev/null @@ -1,33 +0,0 @@ -@layer base { - /* kumbh-sans-regular */ - @font-face { - font-family: "Kumbh Sans"; - font-style: normal; - font-weight: 400; - src: url("/fonts/kumbh-sans-regular.woff2") format("woff2"); - } - - /* kumbh-sans-700 */ - @font-face { - font-family: "Kumbh Sans"; - font-style: normal; - font-weight: 700; - src: url("/fonts/kumbh-sans-700.woff2") format("woff2"); - } - - /* montserrat-regular */ - @font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 400; - src: url("/fonts/montserrat-regular.woff2") format("woff2"); - } - - /* montserrat-600 - latin */ - @font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 600; - src: url("/fonts/montserrat-600.woff2") format("woff2"); - } -} diff --git a/app/Resources/styles/index.css b/app/Resources/styles/index.css deleted file mode 100644 index 185afd4f..00000000 --- a/app/Resources/styles/index.css +++ /dev/null @@ -1,13 +0,0 @@ -@import "./tailwind.css"; -@import "./fonts.css"; -@import "./layout.css"; -@import "./breadcrumb.css"; -@import "./dropdown.css"; -@import "./multiSelect.css"; -@import "./radioBtn.css"; -@import "./switch.css"; -@import "./charts.css"; -@import "./status.css"; -@import "./tabs.css"; -@import "./radioToggler.css"; -@import "./formInputTabs.css"; diff --git a/app/Resources/styles/layout.css b/app/Resources/styles/layout.css deleted file mode 100644 index e5535241..00000000 --- a/app/Resources/styles/layout.css +++ /dev/null @@ -1,27 +0,0 @@ -/* Admin layout */ -.holy-grail-grid { - @apply grid min-h-screen overflow-y-auto; - grid-template: 1fr auto / auto 1fr; - - & .holy-grail-sidebar { - @apply col-start-1 col-end-2 row-start-1 row-end-3 w-80; - } - - & .holy-grail-main { - @apply w-full col-start-1 col-end-3 row-start-1 row-end-2; - } - - & .holy-grail-footer { - @apply w-full col-start-1 col-end-3 row-start-2 row-end-3; - } - - @screen md { - & .holy-grail-main { - @apply col-start-2; - } - - & .holy-grail-footer { - @apply col-start-2; - } - } -} diff --git a/app/Resources/styles/multiSelect.css b/app/Resources/styles/multiSelect.css deleted file mode 100644 index 22dde765..00000000 --- a/app/Resources/styles/multiSelect.css +++ /dev/null @@ -1,183 +0,0 @@ -/*=============================== -= MultiSelect = -===============================*/ - -@layer components { - .multiselect { - @apply relative; - - &:focus { - @apply outline-none ring; - } - &:last-child { - @apply mb-0; - } - &.is-disabled { - &.multiselect__inner, - &.multiselect__input { - @apply bg-gray-300 cursor-not-allowed select-none; - } - &.multiselect__item { - @apply cursor-not-allowed; - } - } - - & [hidden] { - @apply hidden; - } - } - - .multiselect[data-type*="select-multiple"], - .multiselect[data-type*="text"] { - & .multiselect__inner { - @apply cursor-text; - } - & .multiselect__button { - @apply relative inline-block w-2 pl-4 mt-0 mb-0 ml-1 opacity-75; - background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==); - background-size: 8px; - - &:hover, - &:focus { - @apply opacity-100; - } - } - } - - .multiselect__inner { - @apply inline-block w-full px-2 pt-2 pb-1 overflow-hidden align-top bg-white border rounded; - - &.is-focused, - &.is-open { - @apply ring; - } - &.is-open { - @apply rounded-b-none; - } - &.is-flipped.is-open { - @apply rounded-t-none; - } - } - - .multiselect__list { - @apply p-0 m-0 list-none; - } - - .multiselect__list--multiple { - @apply inline; - - & .multiselect__item { - @apply inline-flex px-2 py-1 mb-1 mr-2 text-sm text-white break-all rounded bg-pine-600; - - &[data-deletable] { - @apply pr-1; - } - & [dir="rtl"] { - @apply ml-2 mr-0; - } - &.is-highlighted { - @apply bg-pine-600; - } - &.is-disabled { - @apply bg-gray-500; - } - } - } - - .multiselect__list--dropdown { - @apply absolute z-10 invisible w-full overflow-hidden break-all bg-white border border-t-0 rounded-b shadow-lg; - top: 100%; - will-change: visibility; - - &.is-active { - @apply visible; - } - &.is-open { - @apply ring; - } - &.is-flipped { - @apply top-auto mt-0 rounded-t; - bottom: 100%; - } - & .multiselect__list { - @apply relative overflow-auto; - max-height: 300px; - -webkit-overflow-scrolling: touch; - will-change: scroll-position; - } - & .multiselect__item { - @apply relative p-3; - - & [dir="rtl"] { - @apply text-right; - } - } - & .multiselect__item--selectable { - @screen sm { - padding-right: 100px; - &:after { - @apply absolute text-sm transform -translate-y-1/2 opacity-0; - content: attr(data-select-text); - right: 10px; - top: 50%; - } - & [dir="rtl"] { - @apply text-right; - padding-left: 100px; - padding-right: 10px; - &:after { - @apply right-auto; - left: 10px; - } - } - } - &.is-highlighted { - @apply bg-gray-100; - &:after { - @apply opacity-50; - } - } - } - } - - .multiselect__item { - @apply cursor-default; - } - - .multiselect__item--selectable { - @apply cursor-pointer; - } - - .multiselect__item--disabled { - @apply opacity-50 cursor-not-allowed select-none; - } - - .multiselect__heading { - @apply p-3 font-semibold text-gray-600 border-b; - } - - .multiselect__button { - @apply bg-transparent bg-center bg-no-repeat border-0 appearance-none cursor-pointer; - text-indent: -9999px; - - &:focus { - @apply outline-none; - } - } - - .multiselect__input { - @apply inline-block max-w-full py-1 pl-1 mb-1 align-baseline bg-transparent border-0 rounded-none; - &:focus { - @apply outline-none; - } - & [dir="rtl"] { - @apply pl-0 pr-1; - } - } - - .multiselect__placeholder { - @apply opacity-50; - } -} - -/*===== End of Multiselect ======*/ diff --git a/app/Resources/styles/radioBtn.css b/app/Resources/styles/radioBtn.css deleted file mode 100644 index 0abe1a6e..00000000 --- a/app/Resources/styles/radioBtn.css +++ /dev/null @@ -1,26 +0,0 @@ -@layer components { - .form-radio-btn { - @apply absolute opacity-0; - } - - .form-radio-btn:focus + label { - @apply ring; - } - - .form-radio-btn + label { - @apply inline-block px-2 py-1 text-sm text-black bg-white border rounded cursor-pointer; - - &:hover { - @apply bg-pine-100; - } - } - - .form-radio-btn:checked + label { - @apply text-white bg-pine-600; - - &::before { - @apply mr-2 text-pine-200; - content: "✓"; - } - } -} diff --git a/app/Resources/styles/status.css b/app/Resources/styles/status.css deleted file mode 100644 index e3d2b794..00000000 --- a/app/Resources/styles/status.css +++ /dev/null @@ -1,22 +0,0 @@ -@layer components { - .status-content { - & a { - @apply text-sm font-semibold text-pine-600 hover:underline; - } - } - - .status-replies > * { - @apply relative; - - & img { - @apply z-20; - } - - &:not(:last-child)::before { - @apply absolute z-10 h-full bg-gray-300 top-8; - content: ""; - left: 3rem; - width: 2px; - } - } -} diff --git a/app/Resources/styles/switch.css b/app/Resources/styles/switch.css deleted file mode 100644 index 3d8a7f3d..00000000 --- a/app/Resources/styles/switch.css +++ /dev/null @@ -1,28 +0,0 @@ -@layer components { - .form-switch { - @apply absolute w-0 h-0 opacity-0; - - &:checked + .form-switch-slider { - @apply bg-pine-600; - } - - &:focus + .form-switch-slider { - @apply ring; - } - - &:checked + .form-switch-slider::before { - @apply transform translate-x-5; - } - } - - .form-switch-slider { - @apply relative inset-0 flex-shrink-0 w-10 h-5 transition duration-200 bg-gray-400 rounded-full cursor-pointer; - - &::before { - @apply absolute w-4 h-4 transition duration-200 bg-white rounded-full ring-1 ring-black ring-opacity-5; - content: ""; - left: 2px; - bottom: 2px; - } - } -} diff --git a/app/Resources/styles/tabs.css b/app/Resources/styles/tabs.css deleted file mode 100644 index f0f279b4..00000000 --- a/app/Resources/styles/tabs.css +++ /dev/null @@ -1,37 +0,0 @@ -@layer components { - .tabset { - @apply grid grid-cols-2; - } - - .tabset > input[type="radio"] { - @apply absolute -left-full; - } - - .tabset .tab-panel { - @apply hidden; - } - - /* Logic for 2 tabs at most */ - .tabset > input:first-child:checked ~ .tab-panels > .tab-panel:first-child, - .tabset > input:nth-child(3):checked ~ .tab-panels > .tab-panel:nth-child(2) { - @apply block; - } - - /* Styling */ - .tabset > label { - @apply relative inline-block w-full px-4 py-3 text-center cursor-pointer opacity-70 hover:opacity-100; - } - - .tabset > input:checked + label::after { - @apply absolute inset-x-0 bottom-0 w-1/2 h-1 mx-auto bg-pine-700; - content: ""; - } - - .tabset > input:checked + label { - @apply font-semibold opacity-100 text-pine-700; - } - - .tabset .tab-panels { - @apply col-span-2 p-6; - } -} diff --git a/app/Resources/types/js/admin.d.ts b/app/Resources/types/js/admin.d.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/app/Resources/types/js/admin.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/app/Resources/types/js/charts.d.ts b/app/Resources/types/js/charts.d.ts deleted file mode 100644 index c3fee8a1..00000000 --- a/app/Resources/types/js/charts.d.ts +++ /dev/null @@ -1 +0,0 @@ -import "core-js"; diff --git a/app/Resources/types/js/install.d.ts b/app/Resources/types/js/install.d.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/app/Resources/types/js/install.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/app/Resources/types/js/map.d.ts b/app/Resources/types/js/map.d.ts deleted file mode 100644 index c3fee8a1..00000000 --- a/app/Resources/types/js/map.d.ts +++ /dev/null @@ -1 +0,0 @@ -import "core-js"; diff --git a/app/Resources/types/js/modules/Charts.d.ts b/app/Resources/types/js/modules/Charts.d.ts deleted file mode 100644 index 2e5108cf..00000000 --- a/app/Resources/types/js/modules/Charts.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const DrawCharts: () => void; -export default DrawCharts; diff --git a/app/Resources/types/js/modules/ClientTimezone.d.ts b/app/Resources/types/js/modules/ClientTimezone.d.ts deleted file mode 100644 index 34444632..00000000 --- a/app/Resources/types/js/modules/ClientTimezone.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const ClientTimezone: () => void; -export default ClientTimezone; diff --git a/app/Resources/types/js/modules/Clipboard.d.ts b/app/Resources/types/js/modules/Clipboard.d.ts deleted file mode 100644 index 9500a96e..00000000 --- a/app/Resources/types/js/modules/Clipboard.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Clipboard: () => void; -export default Clipboard; diff --git a/app/Resources/types/js/modules/DateTimePicker.d.ts b/app/Resources/types/js/modules/DateTimePicker.d.ts deleted file mode 100644 index 9612d403..00000000 --- a/app/Resources/types/js/modules/DateTimePicker.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import "flatpickr/dist/flatpickr.min.css"; -declare const DateTimePicker: () => void; -export default DateTimePicker; diff --git a/app/Resources/types/js/modules/Dropdown.d.ts b/app/Resources/types/js/modules/Dropdown.d.ts deleted file mode 100644 index 5395e564..00000000 --- a/app/Resources/types/js/modules/Dropdown.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Dropdown: () => void; -export default Dropdown; diff --git a/app/Resources/types/js/modules/EpisodesMap.d.ts b/app/Resources/types/js/modules/EpisodesMap.d.ts deleted file mode 100644 index 67f900a5..00000000 --- a/app/Resources/types/js/modules/EpisodesMap.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import "leaflet.markercluster/dist/MarkerCluster.css"; -import "leaflet.markercluster/dist/MarkerCluster.Default.css"; -import "leaflet/dist/leaflet.css"; -declare const DrawEpisodesMaps: () => void; -export default DrawEpisodesMaps; diff --git a/app/Resources/types/js/modules/Map.d.ts b/app/Resources/types/js/modules/Map.d.ts deleted file mode 100644 index 4fe78599..00000000 --- a/app/Resources/types/js/modules/Map.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const DrawMaps: () => void; -export default DrawMaps; diff --git a/app/Resources/types/js/modules/MarkdownEditor.d.ts b/app/Resources/types/js/modules/MarkdownEditor.d.ts deleted file mode 100644 index f8d018b6..00000000 --- a/app/Resources/types/js/modules/MarkdownEditor.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import "prosemirror-example-setup/style/style.css"; -import "prosemirror-menu/style/menu.css"; -import "prosemirror-view/style/prosemirror.css"; -declare const MarkdownEditor: () => void; -export default MarkdownEditor; diff --git a/app/Resources/types/js/modules/Modal.d.ts b/app/Resources/types/js/modules/Modal.d.ts deleted file mode 100644 index 99d06ce4..00000000 --- a/app/Resources/types/js/modules/Modal.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Modal: () => void; -export default Modal; diff --git a/app/Resources/types/js/modules/MultiSelect.d.ts b/app/Resources/types/js/modules/MultiSelect.d.ts deleted file mode 100644 index 0f708a24..00000000 --- a/app/Resources/types/js/modules/MultiSelect.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const MultiSelect: () => void; -export default MultiSelect; diff --git a/app/Resources/types/js/modules/PublishMessageWarning.d.ts b/app/Resources/types/js/modules/PublishMessageWarning.d.ts deleted file mode 100644 index c9a7b80f..00000000 --- a/app/Resources/types/js/modules/PublishMessageWarning.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const PublishMessageWarning: () => void; -export default PublishMessageWarning; diff --git a/app/Resources/types/js/modules/SidebarToggler.d.ts b/app/Resources/types/js/modules/SidebarToggler.d.ts deleted file mode 100644 index 53739967..00000000 --- a/app/Resources/types/js/modules/SidebarToggler.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const SidebarToggler: () => void; -export default SidebarToggler; diff --git a/app/Resources/types/js/modules/Slugify.d.ts b/app/Resources/types/js/modules/Slugify.d.ts deleted file mode 100644 index 532945fd..00000000 --- a/app/Resources/types/js/modules/Slugify.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Slugify: () => void; -export default Slugify; diff --git a/app/Resources/types/js/modules/Soundbites.d.ts b/app/Resources/types/js/modules/Soundbites.d.ts deleted file mode 100644 index b35a4256..00000000 --- a/app/Resources/types/js/modules/Soundbites.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Soundbites: () => void; -export default Soundbites; diff --git a/app/Resources/types/js/modules/ThemePicker.d.ts b/app/Resources/types/js/modules/ThemePicker.d.ts deleted file mode 100644 index 385f044b..00000000 --- a/app/Resources/types/js/modules/ThemePicker.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const ThemePicker: () => void; -export default ThemePicker; diff --git a/app/Resources/types/js/modules/Time.d.ts b/app/Resources/types/js/modules/Time.d.ts deleted file mode 100644 index e04a63d4..00000000 --- a/app/Resources/types/js/modules/Time.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Time: () => void; -export default Time; diff --git a/app/Resources/types/js/modules/Toggler.d.ts b/app/Resources/types/js/modules/Toggler.d.ts deleted file mode 100644 index 3157ee54..00000000 --- a/app/Resources/types/js/modules/Toggler.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Toggler: () => void; -export default Toggler; diff --git a/app/Resources/types/js/modules/Tooltip.d.ts b/app/Resources/types/js/modules/Tooltip.d.ts deleted file mode 100644 index d733d7a3..00000000 --- a/app/Resources/types/js/modules/Tooltip.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const Tooltip: () => void; -export default Tooltip; diff --git a/app/Resources/types/js/my-element.d.ts b/app/Resources/types/js/my-element.d.ts deleted file mode 100644 index 6e7ac68a..00000000 --- a/app/Resources/types/js/my-element.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { LitElement } from "lit"; -declare class MyElement extends LitElement { - render(): import("lit-html").TemplateResult<1>; -} -export default MyElement; diff --git a/app/Resources/types/js/podcast.d.ts b/app/Resources/types/js/podcast.d.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/app/Resources/types/js/podcast.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/app/Validation/FileRules.php b/app/Validation/FileRules.php index 6b6ed3f3..2a149d46 100644 --- a/app/Validation/FileRules.php +++ b/app/Validation/FileRules.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ @@ -11,13 +11,15 @@ declare(strict_types=1); namespace App\Validation; use CodeIgniter\Validation\FileRules as ValidationFileRules; +use Override; class FileRules extends ValidationFileRules { /** * Checks an uploaded file to verify that the dimensions are within a specified allowable dimension. */ - public function min_dims(string $blank = null, string $params): bool + #[Override] + public function min_dims(?string $blank = null, string $params = ''): bool { // Grab the file name off the top of the $params // after we split it. @@ -57,9 +59,9 @@ class FileRules extends ValidationFileRules //-------------------------------------------------------------------- /** - * Checks an uploaded file to verify that the image ratio is of 1:1 + * Checks an uploaded image to verify that the ratio corresponds to the params */ - public function is_image_squared(string $blank = null, string $params): bool + public function is_image_ratio(?string $blank = null, string $params = ''): bool { // Grab the file name off the top of the $params // after we split it. @@ -79,12 +81,14 @@ class FileRules extends ValidationFileRules return true; } - // Get uploaded image size - $info = getimagesize($file->getTempName()); - $fileWidth = $info[0]; - $fileHeight = $info[1]; + // Get Parameter sizes + $x = $params[0] ?? 1; + $y = $params[1] ?? 1; - if ($fileWidth !== $fileHeight) { + // Get uploaded image size + [0 => $fileWidth, 1 => $fileHeight] = getimagesize($file->getTempName()); + + if (($x / $y) !== ($fileWidth / $fileHeight)) { return false; } } @@ -93,4 +97,43 @@ class FileRules extends ValidationFileRules } //-------------------------------------------------------------------- + + /** + * Checks that an uploaded json file's content is valid + */ + public function is_json(?string $blank = null, string $params = ''): bool + { + // Grab the file name off the top of the $params + // after we split it. + $params = explode(',', $params); + $name = array_shift($params); + + if (! ($files = $this->request->getFileMultiple($name))) { + $files = [$this->request->getFile($name)]; + } + + foreach ($files as $file) { + if ($file === null) { + return false; + } + + if ($file->getError() === UPLOAD_ERR_NO_FILE) { + return true; + } + + $content = file_get_contents($file->getTempName()); + + if ($content === false) { + return false; + } + + json_decode($content); + + if (json_last_error() !== JSON_ERROR_NONE) { + return false; + } + } + + return true; + } } diff --git a/app/Validation/OtherRules.php b/app/Validation/OtherRules.php new file mode 100644 index 00000000..74782809 --- /dev/null +++ b/app/Validation/OtherRules.php @@ -0,0 +1,29 @@ + 'alert', + ]; + + /** + * @var 'default'|'success'|'danger'|'warning' + */ + protected string $variant = 'default'; + + #[Override] + public function render(): string + { + $variantData = match ($this->variant) { + 'success' => [ + 'class' => 'text-pine-900 bg-pine-100 border-pine-300', + 'glyph' => 'check-fill', // @icon("check-fill") + ], + 'danger' => [ + 'class' => 'text-red-900 bg-red-100 border-red-300', + 'glyph' => 'close-fill', // @icon("close-fill") + ], + 'warning' => [ + 'class' => 'text-yellow-900 bg-yellow-100 border-yellow-300', + 'glyph' => 'alert-fill', // @icon("alert-fill") + ], + default => [ + 'class' => 'text-blue-900 bg-blue-100 border-blue-300', + 'glyph' => 'error-warning-fill', // @icon("error-warning-fill") + ], + }; + + $glyph = icon(($this->glyph === '' ? $variantData['glyph'] : $this->glyph), [ + 'class' => 'flex-shrink-0 mr-2 text-lg', + ]); + $title = $this->title === '' ? '' : '
' . $this->title . '
'; + $this->mergeClass('inline-flex w-full p-2 text-sm border rounded '); + $this->mergeClass($variantData['class']); + + return <<getStringifiedAttributes()}>{$glyph}
{$title}

{$this->slot}

+ HTML; + } +} diff --git a/app/Views/Components/Button.php b/app/Views/Components/Button.php new file mode 100644 index 00000000..90d2ca63 --- /dev/null +++ b/app/Views/Components/Button.php @@ -0,0 +1,116 @@ + 'boolean', + 'isExternal' => 'boolean', + ]; + + protected string $uri = ''; + + protected string $variant = 'default'; + + /** + * @var 'small'|'base'|'large' + */ + protected string $size = 'base'; + + protected string $iconLeft = ''; + + protected string $iconRight = ''; + + protected bool $isSquared = false; + + protected bool $isExternal = false; + + #[Override] + public function render(): string + { + $this->mergeClass('shadow gap-x-2 flex-shrink-0 inline-flex items-center justify-center font-semibold rounded-full'); + + $variantClass = match ($this->variant) { + 'primary' => 'text-accent-contrast bg-accent-base hover:bg-accent-hover', + 'secondary' => 'ring-2 ring-accent-base ring-inset text-accent-base bg-white hover:border-accent-hover hover:text-accent-hover hover:ring-accent-hover', + 'danger' => 'bg-red-50 ring-2 ring-red-700 ring-inset text-red-700 hover:ring-red-800 hover:text-red-800', + 'warning' => 'bg-yellow-50 ring-2 ring-yellow-700 ring-inset text-yellow-700 hover:ring-yellow-800 hover:text-yellow-800', + 'info' => 'bg-blue-50 ring-2 ring-blue-700 ring-inset text-blue-700 hover:ring-blue-800 hover:text-blue-800', + 'disabled' => 'text-black bg-gray-300 cursor-not-allowed', + default => 'text-black bg-gray-50 hover:bg-gray-200', + }; + + $sizeClass = match ($this->size) { + 'small' => 'text-xs leading-6', + 'large' => 'text-base leading-6', + default => 'text-sm leading-5', + }; + + $iconSizeClass = match ($this->size) { + 'small' => 'text-sm', + 'large' => 'text-2xl', + default => 'text-lg', + }; + + $basePaddings = match ($this->size) { + 'small' => 'px-3 py-1', + 'large' => 'px-4 py-2', + default => 'px-3 py-2', + }; + + $squaredPaddings = match ($this->size) { + 'small' => 'p-1', + 'large' => 'p-3', + default => 'p-2', + }; + + $this->mergeClass($variantClass); + $this->mergeClass($sizeClass); + + if ($this->isSquared) { + $this->mergeClass($squaredPaddings); + } else { + $this->mergeClass($basePaddings); + } + + if ($this->iconLeft !== '' || $this->iconRight !== '') { + $this->slot = '' . $this->slot . ''; + } + + if ($this->iconLeft !== '') { + $this->slot = icon($this->iconLeft, [ + 'class' => 'opacity-75 ' . $iconSizeClass, + ]) . $this->slot; + } + + if ($this->iconRight !== '') { + $this->slot .= icon($this->iconRight, [ + 'class' => 'opacity-75 ' . $iconSizeClass, + ]); + } + + if ($this->uri !== '') { + $tagName = 'a'; + $this->attributes['href'] = $this->uri; + if ($this->isExternal) { + $this->attributes['target'] = '_blank'; + $this->attributes['rel'] = 'noopener noreferrer'; + } + } else { + $tagName = 'button'; + $this->attributes['type'] ??= 'button'; + } + + return <<getStringifiedAttributes()}>{$this->slot} + HTML; + } +} diff --git a/app/Views/Components/Charts/Bar.php b/app/Views/Components/Charts/Bar.php new file mode 100644 index 00000000..d5fbc568 --- /dev/null +++ b/app/Views/Components/Charts/Bar.php @@ -0,0 +1,10 @@ +subtitle !== '') { + $subtitleBlock = '

' . $this->subtitle . '

'; + } + + $this->mergeClass('bg-elevated border-3 rounded-xl border-subtle'); + + return <<getStringifiedAttributes()}> +

{$this->title}

+ {$subtitleBlock} +
+ + HTML; + } +} diff --git a/app/Views/Components/Charts/Map.php b/app/Views/Components/Charts/Map.php new file mode 100644 index 00000000..d010ee61 --- /dev/null +++ b/app/Views/Components/Charts/Map.php @@ -0,0 +1,10 @@ +subtitle = html_entity_decode($value); + } + + #[Override] + public function render(): string + { + $glyph = (string) icon($this->glyph, [ + 'class' => 'flex-shrink-0 bg-base rounded-full w-8 h-8 p-2 text-accent-base', + ]); + + if ($this->href !== '') { + $chevronRight = icon('arrow-right-s-fill'); + $viewLang = lang('Common.view'); + return << +
{$glyph}
{$this->title}
{$viewLang}{$chevronRight}

{$this->subtitle}

+
{$this->slot}
+ + HTML; + } + + return << +
{$glyph}
{$this->title}

{$this->subtitle}

+
{$this->slot}
+ + HTML; + } +} diff --git a/app/Views/Components/DropdownMenu.php b/app/Views/Components/DropdownMenu.php new file mode 100644 index 00000000..992ef22e --- /dev/null +++ b/app/Views/Components/DropdownMenu.php @@ -0,0 +1,76 @@ + 'number', + 'offsetY' => 'number', + 'items' => 'array', + ]; + + protected string $id; + + protected string $labelledby; + + protected string $placement = 'bottom-end'; + + protected int $offsetX = 0; + + protected int $offsetY = 0; + + protected array $items = []; + + public function setItems(string $value): void + { + $this->items = json_decode(htmlspecialchars_decode($value), true); + } + + #[Override] + public function render(): string + { + if ($this->items === []) { + throw new Exception('Dropdown menu has no items'); + } + + $menuItems = ''; + foreach ($this->items as $item) { + switch ($item['type']) { + case 'link': + $menuItems .= anchor($item['uri'], $item['title'], [ + 'class' => 'inline-flex gap-x-1 items-center px-4 py-1 hover:bg-highlight' . (array_key_exists('class', $item) ? ' ' . $item['class'] : ''), + ]); + break; + case 'html': + $menuItems .= htmlspecialchars_decode((string) $item['content']); + break; + case 'separator': + $menuItems .= '
'; + break; + default: + break; + } + } + + $this->mergeClass('absolute flex flex-col py-2 rounded-lg z-60 whitespace-nowrap text-skin-base border-contrast bg-elevated border-3'); + $this->attributes['id'] = $this->id; + $this->attributes['aria-labelledby'] = $this->labelledby; + $this->attributes['data-dropdown'] = 'menu'; + $this->attributes['data-dropdown-placement'] = $this->placement; + $this->attributes['data-dropdown-offset-x'] = $this->offsetX; + $this->attributes['data-dropdown-offset-y'] = $this->offsetY; + + return <<getStringifiedAttributes()}>{$menuItems} + HTML; + } +} diff --git a/app/Views/Components/Forms/Checkbox.php b/app/Views/Components/Forms/Checkbox.php new file mode 100644 index 00000000..08c94bc5 --- /dev/null +++ b/app/Views/Components/Forms/Checkbox.php @@ -0,0 +1,62 @@ + 'boolean', + ]; + + protected string $hint = ''; + + protected string $helper = ''; + + #[Override] + public function render(): string + { + $checkboxInput = form_checkbox( + [ + 'id' => $this->id, + 'name' => $this->name, + 'class' => 'form-checkbox bg-elevated text-accent-base border-contrast border-3 focus:ring-accent w-6 h-6 transition', + ], + 'yes', + in_array($this->getValue(), ['yes', 'true', 'on', '1'], true), + ); + + $hint = $this->hint === '' ? '' : new Hint([ + 'class' => 'ml-1', + 'slot' => $this->hint, + ])->render(); + + $this->mergeClass('inline-flex items-start gap-x-2'); + + $helperText = ''; + if ($this->helper !== '') { + $helperId = $this->name . 'Help'; + $helperText = new Helper([ + 'id' => $helperId, + 'slot' => $this->helper, + 'class' => '-mt-1', + ])->render(); + $this->attributes['aria-describedby'] = $helperId; + } + + return <<getStringifiedAttributes()}>{$checkboxInput} +
+ {$this->slot}{$hint} + {$helperText} +
+ + HTML; + } +} diff --git a/app/Views/Components/Forms/CodeEditor.php b/app/Views/Components/Forms/CodeEditor.php new file mode 100644 index 00000000..ab20988f --- /dev/null +++ b/app/Views/Components/Forms/CodeEditor.php @@ -0,0 +1,35 @@ + '6', + 'class' => 'bg-elevated w-full rounded-lg border-3 border-contrast focus:border-contrast focus-within:ring-accent transition', + ]; + + protected string $lang = ''; + + public function setValue(string $value): void + { + $this->value = htmlspecialchars_decode($value); + } + + #[Override] + public function render(): string + { + $this->attributes['slot'] = 'textarea'; + $textarea = form_textarea($this->attributes, $this->getValue()); + + return <<{$textarea} + HTML; + } +} diff --git a/app/Views/Components/Forms/ColorRadioButton.php b/app/Views/Components/Forms/ColorRadioButton.php new file mode 100644 index 00000000..f1ff3fde --- /dev/null +++ b/app/Views/Components/Forms/ColorRadioButton.php @@ -0,0 +1,45 @@ + 'boolean', + ]; + + protected bool $isSelected = false; + + #[Override] + public function render(): string + { + $data = [ + 'id' => $this->value, + 'name' => $this->name, + 'class' => 'color-radio-btn', + ]; + + if ($this->isRequired) { + $data['required'] = 'required'; + } + + $radioInput = form_radio( + $data, + $this->value, + old($this->name) ? old($this->name) === $this->value : $this->isSelected, + ); + + return <<getStringifiedAttributes()}> + {$radioInput} + + + HTML; + } +} diff --git a/app/Views/Components/Forms/DatetimePicker.php b/app/Views/Components/Forms/DatetimePicker.php new file mode 100644 index 00000000..1267ffef --- /dev/null +++ b/app/Views/Components/Forms/DatetimePicker.php @@ -0,0 +1,40 @@ + 'datetime', + ]; + + #[Override] + public function render(): string + { + $dateInput = form_input([ + 'name' => $this->name, + 'class' => 'rounded-l-lg border-0 border-rounded-r-none flex-1 focus:ring-0', + 'data-input' => '', + ], $this->getValue()); + + $clearLabel = lang( + 'Episode.publish_form.scheduled_publication_date_clear', + ); + $closeIcon = icon('close-fill'); + + $this->mergeClass('flex border-3 rounded-lg border-contrast focus-within:ring-accent transition'); + + return <<getStringifiedAttributes()}> + {$dateInput} + + + HTML; + } +} diff --git a/app/Views/Components/Forms/Field.php b/app/Views/Components/Forms/Field.php new file mode 100644 index 00000000..0efc0d09 --- /dev/null +++ b/app/Views/Components/Forms/Field.php @@ -0,0 +1,86 @@ + 'boolean', + 'isReadonly' => 'boolean', + ]; + + protected string $name; + + protected string $label; + + protected bool $isRequired = false; + + protected bool $isReadonly = false; + + protected string $as = 'Input'; + + protected string $hint = ''; + + protected string $helper = ''; + + #[Override] + public function render(): string + { + $helperText = ''; + if ($this->helper !== '') { + $helperId = $this->name . 'Help'; + $helperText = new Helper([ + 'id' => $helperId, + 'slot' => $this->helper, + ])->render(); + $this->attributes['aria-describedby'] = $helperId; + } + + $labelAttributes = [ + 'for' => $this->name, + 'isOptional' => $this->isRequired ? 'false' : 'true', + 'class' => '-mb-1', + 'slot' => $this->label, + ]; + if ($this->hint !== '') { + $labelAttributes['hint'] = $this->hint; + } + $label = new Label($labelAttributes); + + $this->mergeClass('flex flex-col'); + $fieldClass = $this->attributes['class']; + + unset($this->attributes['class']); + + $this->attributes['name'] = $this->name; + $this->attributes['isRequired'] = var_export($this->isRequired, true); + $this->attributes['isReadonly'] = var_export($this->isReadonly, true); + $element = __NAMESPACE__ . '\\' . $this->as; + $fieldElement = new $element($this->attributes); + + return << + {$label->render()} + {$helperText} +
+ {$fieldElement->render()} +
+ + HTML; + } +} diff --git a/app/Views/Components/Forms/FormComponent.php b/app/Views/Components/Forms/FormComponent.php new file mode 100644 index 00000000..bcc46b26 --- /dev/null +++ b/app/Views/Components/Forms/FormComponent.php @@ -0,0 +1,82 @@ + 'boolean', + 'isReadonly' => 'boolean', + ]; + + protected string $id; + + protected string $name; + + /** + * @var string|string[]|null + */ + protected string|array|null $value = null; + + /** + * @var string|string[]|null + */ + protected string|array|null $defaultValue = null; + + protected bool $isRequired = false; + + protected bool $isReadonly = false; + + /** + * @param array $attributes + */ + public function __construct(array $attributes) + { + $parentVars = get_class_vars(self::class); + $this->casts = [...$parentVars['casts'], ...$this->casts]; + $this->props = [...$parentVars['props'], $this->props]; + + parent::__construct($attributes); + + if (! isset($this->id)) { + $this->id = $this->name; + } + + $this->attributes['id'] = $this->id; + $this->attributes['name'] = $this->name; + + if ($this->isRequired) { + $this->attributes['required'] = 'required'; + } + + if ($this->isReadonly) { + $this->attributes['readonly'] = 'readonly'; + } + } + + protected function getValue(): string|array + { + $valueCast = $this->casts['value'] ?? ''; + if ($valueCast === 'array') { + return old($this->name, in_array($this->value, [[], null], true) ? $this->defaultValue : $this->value) ?? []; + } + + return old( + $this->name, + in_array($this->value, ['', null], true) ? $this->defaultValue : $this->value, + ) ?? ''; + } +} diff --git a/app/Views/Components/Forms/Helper.php b/app/Views/Components/Forms/Helper.php new file mode 100644 index 00000000..fbc895d1 --- /dev/null +++ b/app/Views/Components/Forms/Helper.php @@ -0,0 +1,23 @@ +mergeClass('form-helper'); + + return <<getStringifiedAttributes()}>{$this->slot} + HTML; + } +} diff --git a/app/Views/Components/Forms/Input.php b/app/Views/Components/Forms/Input.php new file mode 100644 index 00000000..a45d3224 --- /dev/null +++ b/app/Views/Components/Forms/Input.php @@ -0,0 +1,36 @@ +mergeClass('w-full border-contrast rounded-lg focus:border-contrast border-3 focus-within:ring-accent transition'); + + if ($this->type === 'file') { + $this->mergeClass('file:px-3 file:py-2 file:h-[40px] file:font-semibold file:text-accent-hover file:text-sm file:rounded-none file:border-none file:bg-base file:cursor-pointer'); + } else { + $this->mergeClass('px-3 py-2'); + } + + if ($this->isReadonly) { + $this->mergeClass('bg-base'); + } else { + $this->mergeClass('bg-elevated'); + } + + $this->attributes['type'] = $this->type; + + return form_input($this->attributes, $this->getValue()); + } +} diff --git a/app/Views/Components/Forms/Label.php b/app/Views/Components/Forms/Label.php new file mode 100644 index 00000000..3f8af6f6 --- /dev/null +++ b/app/Views/Components/Forms/Label.php @@ -0,0 +1,45 @@ + 'boolean', + ]; + + protected string $for; + + protected string $hint = ''; + + protected bool $isOptional = false; + + #[Override] + public function render(): string + { + $this->mergeClass('text-sm font-semibold'); + + $optionalText = $this->isOptional ? '(' . + lang('Common.optional') . + ')' : ''; + + $hint = $this->hint === '' ? '' : new Hint([ + 'class' => 'ml-1', + 'slot' => $this->hint, + ])->render(); + + $this->attributes['for'] = $this->for; + + return <<getStringifiedAttributes()}>{$this->slot}{$optionalText}{$hint} + HTML; + } +} diff --git a/app/Views/Components/Forms/MarkdownEditor.php b/app/Views/Components/Forms/MarkdownEditor.php new file mode 100644 index 00000000..0549fd05 --- /dev/null +++ b/app/Views/Components/Forms/MarkdownEditor.php @@ -0,0 +1,122 @@ +disallowList = explode(',', $value); + } + + #[Override] + public function render(): string + { + $this->mergeClass('w-full flex flex-col bg-elevated border-3 border-contrast rounded-lg overflow-hidden focus-within:ring-accent transition'); + $wrapperClass = $this->attributes['class']; + + $this->attributes['class'] = 'bg-elevated border-none focus:border-none focus:outline-none focus:ring-0 w-full h-full'; + $this->attributes['rows'] = 6; + + $textarea = form_textarea( + $this->attributes, + $this->getValue(), + ); + $markdownIcon = (string) icon('markdown-fill', [ + 'class' => 'mr-1 text-lg opacity-40', + ]); + + $translations = [ + 'write' => lang('Common.forms.editor.write'), + 'preview' => lang('Common.forms.editor.preview'), + 'help' => lang('Common.forms.editor.help'), + ]; + + $toolbarGroups = [ + [ + [ + 'name' => 'header', + 'tag' => 'md-header', + 'icon' => (string) icon('heading'), + ], + [ + 'name' => 'bold', + 'tag' => 'md-bold', + 'icon' => (string) icon('bold'), + ], + [ + 'name' => 'italic', + 'tag' => 'md-italic', + 'icon' => (string) icon('italic'), + ], + ], + [ + [ + 'name' => 'unordered-list', + 'tag' => 'md-unordered-list', + 'icon' => (string) icon('list-unordered'), + ], + [ + 'name' => 'ordered-list', + 'tag' => 'md-ordered-list ', + 'icon' => (string) icon('list-ordered-2'), + ], + ], + [ + [ + 'name' => 'link', + 'tag' => 'md-link', + 'icon' => (string) icon('link'), + ], + [ + 'name' => 'image', + 'tag' => 'md-image', + 'icon' => (string) icon('image-add-fill'), + ], + ], + ]; + + $toolbarContent = ''; + foreach ($toolbarGroups as $buttonsGroup) { + $toolbarContent .= '
'; + foreach ($buttonsGroup as $button) { + if (! in_array($button['name'], $this->disallowList, true)) { + $toolbarContent .= '<' . $button['tag'] . ' class="opacity-50 hover:opacity-100 focus:opacity-100">' . $button['icon'] . ''; + } + } + $toolbarContent .= '
'; + } + + return << +
+
+ + + + + {$toolbarContent} +
+
+
+ {$textarea} +
+ + + HTML; + } +} diff --git a/app/Views/Components/Forms/PermalinkEditor.php b/app/Views/Components/Forms/PermalinkEditor.php new file mode 100644 index 00000000..26cf31c9 --- /dev/null +++ b/app/Views/Components/Forms/PermalinkEditor.php @@ -0,0 +1,41 @@ +mergeClass('flex-1 text-xs border-contrast rounded-lg focus:border-contrast border-3 focus-within:ring-accent transition'); + + $this->attributes['slot'] = 'slug-input'; + $input = form_input($this->attributes, $this->getValue()); + + $editLabel = lang('Common.edit'); + $copyLabel = lang('Common.copy'); + $copiedLabel = lang('Common.copied'); + + return << + {$this->label} + + {$this->prefix} + {$input} + + + HTML; + } +} diff --git a/app/Views/Components/Forms/Radio.php b/app/Views/Components/Forms/Radio.php new file mode 100644 index 00000000..beac8525 --- /dev/null +++ b/app/Views/Components/Forms/Radio.php @@ -0,0 +1,38 @@ + 'boolean', + ]; + + protected bool $isChecked = false; + + #[Override] + public function render(): string + { + $radioInput = form_radio( + [ + 'id' => $this->value, + 'name' => $this->name, + 'class' => 'text-accent-base bg-elevated border-contrast border-3 focus:ring-accent w-6 h-6 transition', + ], + $this->getValue(), + old($this->name) ? old($this->name) === $this->value : $this->isChecked, + ); + + $this->mergeClass('inline-flex items-center'); + + return <<getStringifiedAttributes()}>{$radioInput}{$this->slot} + HTML; + } +} diff --git a/app/Views/Components/Forms/RadioButton.php b/app/Views/Components/Forms/RadioButton.php new file mode 100644 index 00000000..9f470b33 --- /dev/null +++ b/app/Views/Components/Forms/RadioButton.php @@ -0,0 +1,61 @@ + 'boolean', + ]; + + protected bool $isSelected = false; + + protected string $description = ''; + + #[Override] + public function render(): string + { + $data = [ + 'id' => $this->value, + 'name' => $this->name, + 'class' => 'form-radio-btn bg-elevated', + ]; + + if ($this->isRequired) { + $data['required'] = 'required'; + } + + $this->mergeClass('relative w-full'); + + $descriptionText = ''; + if ($this->description !== '') { + $describerId = $this->name . 'Help'; + $descriptionText = <<{$this->description} + HTML; + $data['aria-describedby'] = $describerId; + } + + $radioInput = form_radio( + $data, + $this->getValue(), + old($this->name) ? old($this->name) === $this->value : $this->isSelected, + ); + + return <<getStringifiedAttributes()}"> + {$radioInput} + + + HTML; + } +} diff --git a/app/Views/Components/Forms/RadioGroup.php b/app/Views/Components/Forms/RadioGroup.php new file mode 100644 index 00000000..776ff8f2 --- /dev/null +++ b/app/Views/Components/Forms/RadioGroup.php @@ -0,0 +1,70 @@ + 'array', + ]; + + protected string $label; + + /** + * @var array{value:string,label:string,hint?:string} + */ + protected array $options = []; + + protected string $hint = ''; + + protected string $helper = ''; + + #[Override] + public function render(): string + { + $this->mergeClass('flex flex-col'); + $options = ''; + foreach ($this->options as $option) { + $radioButtonData = [ + 'value' => $option['value'], + 'name' => $this->name, + 'slot' => $option['label'], + 'description' => $option['description'] ?? '', + 'isSelected' => var_export($this->getValue() === '' ? $option['value'] === $this->options[0]['value'] : $option['value'] === $this->getValue(), true), + 'isRequired' => var_export($this->isRequired, true), + ]; + + $options .= new RadioButton($radioButtonData)->render(); + } + + $helperText = ''; + if ($this->helper !== '') { + $helperId = $this->name . 'Help'; + $helperText = new Helper([ + 'id' => $helperId, + 'slot' => $this->helper, + ])->render(); + $this->attributes['aria-describedby'] = $helperId; + } + + $hint = $this->hint === '' ? '' : new Hint([ + 'class' => 'ml-1', + 'slot' => $this->hint, + ])->render(); + + return <<getStringifiedAttributes()}> + {$this->label}{$hint} + {$helperText} +
{$options}
+ + HTML; + } +} diff --git a/app/Views/Components/Forms/Section.php b/app/Views/Components/Forms/Section.php new file mode 100644 index 00000000..d50baaed --- /dev/null +++ b/app/Views/Components/Forms/Section.php @@ -0,0 +1,33 @@ +subtitle === '' ? '' : '

' . $this->subtitle . '

'; + + $this->mergeClass('w-full p-4 sm:p-6 md:p-8 bg-elevated border-3 flex flex-col items-start border-subtle rounded-xl'); + + return <<getStringifiedAttributes()}> + {$this->title} + {$subtitle} +
{$this->slot}
+ + HTML; + } +} diff --git a/app/Views/Components/Forms/Select.php b/app/Views/Components/Forms/Select.php new file mode 100644 index 00000000..b62c6942 --- /dev/null +++ b/app/Views/Components/Forms/Select.php @@ -0,0 +1,47 @@ + 'array', + ]; + + /** + * @var array> + */ + protected array $options = []; + + #[Override] + public function render(): string + { + $this->mergeClass('w-full focus:border-contrast border-3 rounded-lg bg-elevated border-contrast'); + $defaultAttributes = [ + 'data-select-text' => lang('Common.forms.multiSelect.selectText'), + 'data-loading-text' => lang('Common.forms.multiSelect.loadingText'), + 'data-no-results-text' => lang('Common.forms.multiSelect.noResultsText'), + 'data-no-choices-text' => lang('Common.forms.multiSelect.noChoicesText'), + 'data-max-item-text' => lang('Common.forms.multiSelect.maxItemText'), + ]; + $this->attributes = [...$defaultAttributes, ...$this->attributes]; + + $options = ''; + $selected = $this->getValue(); + foreach ($this->options as $option) { + $options .= ''; + } + + $this->attributes['name'] = $this->name; + + return <<getStringifiedAttributes()}>{$options} + HTML; + } +} diff --git a/app/Views/Components/Forms/SelectMulti.php b/app/Views/Components/Forms/SelectMulti.php new file mode 100644 index 00000000..6c09619b --- /dev/null +++ b/app/Views/Components/Forms/SelectMulti.php @@ -0,0 +1,52 @@ + 'array', + 'defaultValue' => 'array', + 'options' => 'array', + ]; + + /** + * @var array> + */ + protected array $options = []; + + #[Override] + public function render(): string + { + $this->mergeClass('w-full bg-elevated border-3 border-contrast rounded-lg relative'); + + $defaultAttributes = [ + 'multiple' => 'multiple', + 'data-select-text' => lang('Common.forms.multiSelect.selectText'), + 'data-loading-text' => lang('Common.forms.multiSelect.loadingText'), + 'data-no-results-text' => lang('Common.forms.multiSelect.noResultsText'), + 'data-no-choices-text' => lang('Common.forms.multiSelect.noChoicesText'), + 'data-max-item-text' => lang('Common.forms.multiSelect.maxItemText'), + ]; + + $this->attributes = [...$defaultAttributes, ...$this->attributes]; + + $options = ''; + $selected = $this->getValue(); + foreach ($this->options as $option) { + $options .= ''; + } + + $this->attributes['name'] = $this->name . '[]'; + + return <<getStringifiedAttributes()}>{$options} + HTML; + } +} diff --git a/app/Views/Components/Forms/Textarea.php b/app/Views/Components/Forms/Textarea.php new file mode 100644 index 00000000..f58e3b98 --- /dev/null +++ b/app/Views/Components/Forms/Textarea.php @@ -0,0 +1,33 @@ + '6', + ]; + + public function setValue(string $value): void + { + $this->value = htmlspecialchars_decode($value); + } + + #[Override] + public function render(): string + { + $this->mergeClass('bg-elevated w-full rounded-lg border-3 border-contrast focus:border-contrast focus-within:ring-accent transition'); + + $this->attributes['id'] = $this->id; + + $textarea = form_textarea($this->attributes, $this->getValue()); + + return << 'boolean', + ]; + + protected string $hint = ''; + + protected string $helper = ''; + + protected bool $isChecked = false; + + #[Override] + public function render(): string + { + $this->mergeClass('relative justify-between inline-flex items-start gap-x-2'); + + $checkbox = form_checkbox( + [ + 'id' => $this->id, + 'name' => $this->name, + 'class' => 'form-switch', + ], + 'yes', + in_array($this->getValue(), ['yes', 'true', 'on', '1'], true), + ); + + $hint = $this->hint === '' ? '' : new Hint([ + 'class' => 'ml-1', + 'slot' => $this->hint, + ])->render(); + + $helperText = ''; + if ($this->helper !== '') { + $helperId = $this->name . 'Help'; + $helperText = new Helper([ + 'id' => $helperId, + 'slot' => $this->helper, + 'class' => '-mt-1', + ])->render(); + $this->attributes['aria-describedby'] = $helperId; + } + + return <<getStringifiedAttributes()}> +
+ {$this->slot}{$hint} + {$helperText} +
+ {$checkbox} + + + HTML; + } +} diff --git a/app/Views/Components/Heading.php b/app/Views/Components/Heading.php new file mode 100644 index 00000000..87d2de6e --- /dev/null +++ b/app/Views/Components/Heading.php @@ -0,0 +1,37 @@ +size) { + 'small' => 'tracking-wide text-base', + 'large' => 'text-3xl', + default => 'text-xl', + }; + + $this->mergeClass('relative z-10 font-bold text-heading-foreground font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-heading-background before:z-[-10]'); + $this->mergeClass($sizeClass); + + return <<tagName} {$this->getStringifiedAttributes()}>{$this->slot}tagName}> + HTML; + } +} diff --git a/app/Views/Components/Hint.php b/app/Views/Components/Hint.php new file mode 100644 index 00000000..c329296f --- /dev/null +++ b/app/Views/Components/Hint.php @@ -0,0 +1,30 @@ + 'bottom', + 'tabindex' => '0', + ]; + + #[Override] + public function render(): string + { + $this->attributes['title'] = $this->slot; + + $this->mergeClass('inline-block align-middle opacity-75'); + + $icon = icon('question-fill'); + + return <<getStringifiedAttributes()}>{$icon} + HTML; + } +} diff --git a/app/Views/Components/IconButton.php b/app/Views/Components/IconButton.php new file mode 100644 index 00000000..7c6f44ad --- /dev/null +++ b/app/Views/Components/IconButton.php @@ -0,0 +1,35 @@ + 'true', + 'title' => $attributes['slot'], + 'data-tooltip' => 'bottom', + ]; + + $allAttributes = [...$attributes, ...$iconButtonAttributes]; + + parent::__construct($allAttributes); + + $glyphSizeClass = match ($this->size) { + 'small' => 'text-sm', + 'large' => 'text-2xl', + default => 'text-lg', + }; + + $this->slot = (string) icon($this->glyph, [ + 'class' => $glyphSizeClass, + ]); + } +} diff --git a/app/Views/Components/Pill.php b/app/Views/Components/Pill.php new file mode 100644 index 00000000..9d76cc5e --- /dev/null +++ b/app/Views/Components/Pill.php @@ -0,0 +1,60 @@ +variant) { + 'primary' => 'text-accent-contrast bg-accent-base border-accent-base', + 'success' => 'text-pine-900 bg-pine-100 border-pine-300', + 'danger' => 'text-red-900 bg-red-100 border-red-300', + 'warning' => 'text-yellow-900 bg-yellow-100 border-yellow-300', + default => 'text-gray-800 bg-gray-100 border-gray-300', + }; + + $sizeClass = match ($this->size) { + 'small' => 'text-xs tracking-wide', + default => 'text-sm', + }; + + $icon = $this->icon !== '' ? icon($this->icon, [ + 'class' => $this->iconClass, + ]) : ''; + + if ($this->hint !== '') { + $this->attributes['data-tooltip'] = 'bottom'; + $this->attributes['title'] = $this->hint; + } + + $this->mergeClass('inline-flex lowercase items-center gap-x-1 px-1 font-semibold border rounded'); + $this->mergeClass($variantClass); + $this->mergeClass($sizeClass); + + return <<getStringifiedAttributes()}>{$icon}{$this->slot} + HTML; + } +} diff --git a/app/Views/Components/ReadMore.php b/app/Views/Components/ReadMore.php new file mode 100644 index 00000000..d55e48d9 --- /dev/null +++ b/app/Views/Components/ReadMore.php @@ -0,0 +1,33 @@ +mergeClass('read-more'); + $this->attributes['style'] = '--line-clamp: 3'; + + return <<getStringifiedAttributes()}> + +
{$this->slot}
+ + + HTML; + } +} diff --git a/app/Views/Components/SeeMore.php b/app/Views/Components/SeeMore.php new file mode 100644 index 00000000..e8e42deb --- /dev/null +++ b/app/Views/Components/SeeMore.php @@ -0,0 +1,29 @@ +mergeClass('see-more'); + $this->attributes['styles'] = '--content-height: 10rem'; + + return <<getStringifiedAttributes()}> + +
{$this->slot}
+ + + HTML; + } +} diff --git a/app/Views/_layout.php b/app/Views/_layout.php deleted file mode 100644 index bf9bcded..00000000 --- a/app/Views/_layout.php +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - <?= $this->renderSection('title') ?> - - - - asset('styles/index.css', 'css') ?> - - - -
-
- -

title - : 'Castopod' ?>

-
-
-
- renderSection('content') ?> -
- - diff --git a/app/Views/_message_block.php b/app/Views/_message_block.php index 692baf70..4f40c4e5 100644 --- a/app/Views/_message_block.php +++ b/app/Views/_message_block.php @@ -1,20 +1,19 @@ -has('message')): ?> -
- -
+has('message')): ?> + has('error')): ?> -
- -
+ has('errors')): ?> -
    - -
  • - -
- + +
    + +
  • + +
+
+ diff --git a/app/Views/admin/_layout.php b/app/Views/admin/_layout.php deleted file mode 100644 index ad660a84..00000000 --- a/app/Views/admin/_layout.php +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - <?= $this->renderSection('title') ?> | Castopod Admin - - - - asset('styles/index.css', 'css') ?> - asset('js/admin.ts', 'js') ?> - - - - - -
-
-
-
- -
-

renderSection( - 'pageTitle', - ) ?>

- renderSection('headerLeft') ?> -
-
-
renderSection( - 'headerRight', - ) ?>
-
-
-
- - renderSection('content') ?> -
-
-
- - 'Castopod ' . - CP_VERSION, - ]) ?> -
- - diff --git a/app/Views/admin/_partials/_user_info.php b/app/Views/admin/_partials/_user_info.php deleted file mode 100644 index 2b2d2eda..00000000 --- a/app/Views/admin/_partials/_user_info.php +++ /dev/null @@ -1,32 +0,0 @@ -
-
- -
-
- email ?> -
-
-
-
- -
-
- username ?> -
-
-
-
- -
-
- [roles) ?>] -
-
-
-
- -
-
- [permissions) ?>] -
-
diff --git a/app/Views/admin/_sidebar.php b/app/Views/admin/_sidebar.php deleted file mode 100644 index 65785a67..00000000 --- a/app/Views/admin/_sidebar.php +++ /dev/null @@ -1,79 +0,0 @@ - [ - 'icon' => 'mic', - 'items' => ['podcast-list', 'podcast-create', 'podcast-import'], - ], - 'persons' => [ - 'icon' => 'folder-user', - 'items' => ['person-list', 'person-create'], - ], - 'fediverse' => [ - 'icon' => 'star-smile', - 'items' => ['fediverse-blocked-actors', 'fediverse-blocked-domains'], - ], - 'users' => ['icon' => 'group', 'items' => ['user-list', 'user-create']], - 'pages' => ['icon' => 'pages', 'items' => ['page-list', 'page-create']], -]; ?> - - - - - - - - - - - diff --git a/app/Views/admin/contributor/add.php b/app/Views/admin/contributor/add.php deleted file mode 100644 index 38f3efa4..00000000 --- a/app/Views/admin/contributor/add.php +++ /dev/null @@ -1,44 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title]) ?> -endSection() ?> - -section('pageTitle') ?> -title]) ?> -endSection() ?> - - -section('content') ?> - -id), [ - 'class' => 'flex flex-col max-w-sm', -]) ?> - - - - 'user', - 'class' => 'form-select mb-4', - 'required' => 'required', - 'placeholder' => lang('Contributor.form.user_placeholder') -]) ?> - - - 'role', - 'class' => 'form-select mb-4', - 'required' => 'required', - 'placeholder' => lang('Contributor.form.role_placeholder') -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/contributor/edit.php b/app/Views/admin/contributor/edit.php deleted file mode 100644 index 33398d99..00000000 --- a/app/Views/admin/contributor/edit.php +++ /dev/null @@ -1,35 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -username]) ?> -endSection() ?> - -section('pageTitle') ?> -username]) ?> -endSection() ?> - - -section('content') ?> - -id, $user->id), [ - 'class' => 'flex flex-col max-w-sm', -]) ?> - - - - 'role', - 'class' => 'form-select mb-4', - 'required' => 'required', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/contributor/list.php b/app/Views/admin/contributor/list.php deleted file mode 100644 index f83064d9..00000000 --- a/app/Views/admin/contributor/list.php +++ /dev/null @@ -1,71 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('headerRight') ?> -id), [ - 'variant' => 'accent', - 'iconLeft' => 'add', -]) ?> -endSection() ?> - - -section('content') ?> - - lang('Contributor.list.username'), - 'cell' => function ($contributor) { - return $contributor->username; - }, - ], - [ - 'header' => lang('Contributor.list.role'), - 'cell' => function ($contributor) { - return lang('Contributor.roles.' . $contributor->podcast_role); - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($contributor, $podcast) { - return button( - lang('Contributor.edit'), - route_to( - 'contributor-edit', - $podcast->id, - $contributor->id, - ), - [ - 'variant' => 'info', - 'size' => 'small', - ], - ['class' => 'mr-2'], - ) . - button( - lang('Contributor.remove'), - route_to( - 'contributor-remove', - $podcast->id, - $contributor->id, - ), - [ - 'variant' => 'danger', - 'size' => 'small', - ], - ['class' => 'mr-2'], - ); - }, - ], - ], - $podcast->contributors, - $podcast, -) ?> - -endSection() ?> diff --git a/app/Views/admin/contributor/view.php b/app/Views/admin/contributor/view.php deleted file mode 100644 index 2aca7825..00000000 --- a/app/Views/admin/contributor/view.php +++ /dev/null @@ -1,28 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - $contributor->username, - 'podcastName' => $contributor->podcast->name, -]) ?> -endSection() ?> - - -section('content') ?> -
-
- Username -
-
- username ?> -
-
-
-
- Role -
-
- podcast_role ?> -
-
-endSection() ?> diff --git a/app/Views/admin/dashboard.php b/app/Views/admin/dashboard.php deleted file mode 100644 index 58bc0229..00000000 --- a/app/Views/admin/dashboard.php +++ /dev/null @@ -1,14 +0,0 @@ - -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - -endsection() ?> diff --git a/app/Views/admin/episode/create.php b/app/Views/admin/episode/create.php deleted file mode 100644 index 77501a20..00000000 --- a/app/Views/admin/episode/create.php +++ /dev/null @@ -1,430 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - - - - - 'audio_file', - 'name' => 'audio_file', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'file', - 'accept' => '.mp3,.m4a', -]) ?> - - - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - 'title', - 'name' => 'title', - 'class' => 'form-input mb-4', - 'value' => old('title'), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - - 'slug', - 'name' => 'slug', - 'class' => 'form-input mb-4', - 'value' => old('slug'), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - -
-
- - 'season_number', - 'name' => 'season_number', - 'class' => 'form-input w-full', - 'value' => old('season_number'), - 'type' => 'number', - ]) ?> -
-
- - 'episode_number', - 'name' => 'episode_number', - 'class' => 'form-input w-full', - 'value' => old('episode_number'), - 'type' => 'number', - ]) ?> -
-
- - - 'mb-4']) ?> - - - - 'full', 'name' => 'type', 'class' => 'form-radio-btn'], - 'full', - old('type') ? old('type') == 'full' : true, - ) ?> - - 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'], - 'trailer', - old('type') && old('type') == 'trailer', - ) ?> - - 'bonus', 'name' => 'type', 'class' => 'form-radio-btn'], - 'bonus', - old('type') && old('type') == 'bonus', - ) ?> - - - - 'flex mb-6 gap-1']) ?> - - - - 'undefined', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'undefined', - old('parental_advisory') - ? old('parental_advisory') === 'undefined' - : true, - ) ?> - - 'clean', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'clean', - old('parental_advisory') && old('parental_advisory') === 'clean', - ) ?> - - 'explicit', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'explicit', - old('parental_advisory') && old('parental_advisory') === 'explicit', - ) ?> - - - - - - - - -
- - 'description', - 'name' => 'description', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('description', '', false), - 'data-editor="markdown"', - ) ?> -
- -
- - 'description_footer', - 'name' => 'description_footer', - 'class' => 'form-textarea', - ], - old( - 'description_footer', - $podcast->episode_description_footer_markdown ?? '', - false, - ), - 'data-editor="markdown"', - ) ?> -
- - - - - - - 'location_name', - 'name' => 'location_name', - 'class' => 'form-input mb-4', - 'value' => old('location_name'), -]) ?> - - - - - 'flex flex-col mb-4']) ?> - (' . - lang('Common.optional') . - ')' . - hint_tooltip(lang('Episode.form.transcript_hint'), 'ml-1') ?> -
- /> - - - /> - - -
-
- 'sr-only'], - lang('Episode.form.transcript_file'), - true, - ) ?> - 'transcript_file', - 'name' => 'transcript_file', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.txt,.html,.srt,.json', - ]) ?> -
-
- 'sr-only'], - lang('Episode.form.transcript_file_remote_url'), - true, - ) ?> - 'transcript_file_remote_url', - 'name' => 'transcript_file_remote_url', - 'class' => 'form-input w-full', - 'type' => 'url', - 'placeholder' => 'https://...', - 'value' => old('transcript_file_remote_url'), - ]) ?> -
-
-
- - - 'flex flex-col mb-4']) ?> - (' . - lang('Common.optional') . - ')' . - hint_tooltip(lang('Episode.form.chapters_hint'), 'ml-1') ?> -
- /> - - - /> - - -
-
- 'sr-only'], - lang('Episode.form.chapters_file'), - true, - ) ?> - 'chapters_file', - 'name' => 'chapters_file', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.json', - ]) ?> -
-
- 'sr-only'], - lang('Episode.form.chapters_file_remote_url'), - true, - ) ?> - 'chapters_file_remote_url', - 'name' => 'chapters_file_remote_url', - 'class' => 'form-input w-full', - 'type' => 'url', - 'placeholder' => 'https://...', - 'value' => old('chapters_file_remote_url'), - ]) ?> -
-
-
- - - - - - - 'custom_rss', - 'name' => 'custom_rss', - 'class' => 'form-textarea', - 'value' => old('custom_rss'), -]) ?> - - - 'block', 'name' => 'block'], - 'yes', - old('block', false), -) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - -endSection() ?> diff --git a/app/Views/admin/episode/edit.php b/app/Views/admin/episode/edit.php deleted file mode 100644 index d394982c..00000000 --- a/app/Views/admin/episode/edit.php +++ /dev/null @@ -1,503 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id, $episode->id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - - - -image->medium_url . - '" - alt="' . - $episode->title . - '" - class="w-48" -/>', -) ?> - - - 'audio_file', - 'name' => 'audio_file', - 'class' => 'form-input mb-4', - 'type' => 'file', - 'accept' => '.mp3,.m4a', -]) ?> - - - - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - 'title', - 'name' => 'title', - 'class' => 'form-input mb-4', - 'value' => old('title', $episode->title), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - - 'slug', - 'name' => 'slug', - 'class' => 'form-input mb-4', - 'value' => old('slug', $episode->slug), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - -
-
- - 'season_number', - 'name' => 'season_number', - 'class' => 'form-input w-full', - 'value' => old('season_number', $episode->season_number), - 'type' => 'number', - ]) ?> -
-
- - 'episode_number', - 'name' => 'episode_number', - 'class' => 'form-input w-full', - 'value' => old('episode_number', $episode->number), - 'type' => 'number', - ]) ?> -
-
- - 'flex mb-4 gap-1']) ?> - - - - 'full', 'name' => 'type', 'class' => 'form-radio-btn'], - 'full', - old('type') ? old('type') === 'full' : $episode->type === 'full', - ) ?> - - 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'], - 'trailer', - old('type') ? old('type') === 'trailer' : $episode->type === 'trailer', - ) ?> - - 'bonus', 'name' => 'type', 'class' => 'form-radio-btn'], - 'bonus', - old('type') ? old('type') === 'bonus' : $episode->type === 'bonus', - ) ?> - - - - 'mb-6']) ?> - - - - 'undefined', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'undefined', - old('parental_advisory') - ? old('parental_advisory') === 'undefined' - : $episode->parental_advisory === null, - ) ?> - - 'clean', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'clean', - old('parental_advisory') - ? old('parental_advisory') === 'clean' - : $episode->parental_advisory === 'clean', - ) ?> - - 'explicit', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'explicit', - old('parental_advisory') - ? old('parental_advisory') === 'explicit' - : $episode->parental_advisory === 'explicit', - ) ?> - - - - - - - - -
- - 'description', - 'name' => 'description', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('description', $episode->description_markdown, false), - 'data-editor="markdown"', - ) ?> -
- -
- - 'description_footer', - 'name' => 'description_footer', - 'class' => 'form-textarea', - ], - old( - 'description_footer', - $podcast->episode_description_footer_markdown ?? '', - false, - ), - 'data-editor="markdown"', - ) ?> -
- - - - - - - 'location_name', - 'name' => 'location_name', - 'class' => 'form-input mb-4', - 'value' => old('location_name', $episode->location_name), -]) ?> - - - - - '“podcast namespace”', - ]), -) ?> - - 'flex flex-col mb-4']) ?> - (' . - lang('Common.optional') . - ')' . - hint_tooltip(lang('Episode.form.transcript_hint'), 'ml-1') ?> -
- transcript_file_remote_url - ? '' - : 'checked' ?> /> - - - transcript_file_remote_url - ? 'checked' - : '' ?> /> - - -
-
- transcript_file): ?> -
- transcript_file_url, - icon('file', 'mr-2 text-gray-500') . - $episode->transcript_file, - [ - 'class' => 'inline-flex items-center text-xs', - 'target' => '_blank', - 'rel' => 'noreferrer noopener', - ], - ) . - anchor( - route_to( - 'transcript-delete', - $podcast->id, - $episode->id, - ), - icon('delete-bin', 'mx-auto'), - [ - 'class' => - 'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang( - 'Episode.form.transcript_file_delete', - ), - ], - ) ?> -
- - 'sr-only'], - lang('Episode.form.transcript_file'), - true, - ) ?> - 'transcript_file', - 'name' => 'transcript_file', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.txt,.html,.srt,.json', - ]) ?> -
-
- 'sr-only'], - lang('Episode.form.transcript_file_remote_url'), - true, - ) ?> - 'transcript_file_remote_url', - 'name' => 'transcript_file_remote_url', - 'class' => 'form-input w-full', - 'type' => 'url', - 'placeholder' => 'https://...', - 'value' => old( - 'transcript_file_remote_url', - $episode->transcript_file_remote_url, - ), - ]) ?> -
-
-
- - - 'flex flex-col mb-4']) ?> - (' . - lang('Common.optional') . - ')' . - hint_tooltip(lang('Episode.form.chapters_hint'), 'ml-1') ?> -
- chapters_file_remote_url - ? '' - : 'checked' ?> /> - - - chapters_file_remote_url - ? 'checked' - : '' ?> /> - - -
-
- chapters_file): ?> -
- chapters_file_url, - icon('file', 'mr-2') . $episode->chapters_file, - [ - 'class' => 'inline-flex items-center text-xs', - 'target' => '_blank', - 'rel' => 'noreferrer noopener', - ], - ) . - anchor( - route_to( - 'chapters-delete', - $podcast->id, - $episode->id, - ), - icon('delete-bin', 'mx-auto'), - [ - 'class' => - 'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang( - 'Episode.form.chapters_file_delete', - ), - ], - ) ?> -
- - 'sr-only'], - lang('Episode.form.chapters_file'), - true, - ) ?> - 'chapters_file', - 'name' => 'chapters_file', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.json', - ]) ?> -
-
- 'sr-only'], - lang('Episode.form.chapters_file_remote_url'), - true, - ) ?> - 'chapters_file_remote_url', - 'name' => 'chapters_file_remote_url', - 'class' => 'form-input w-full', - 'type' => 'url', - 'placeholder' => 'https://...', - 'value' => old( - 'chapters_file_remote_url', - $episode->chapters_file_remote_url, - ), - ]) ?> -
-
-
- - - - - - - 'custom_rss', - 'name' => 'custom_rss', - 'class' => 'form-textarea', - 'value' => old('custom_rss', $episode->custom_rss_string), -]) ?> - - - 'block', 'name' => 'block'], - 'yes', - old('block', $episode->is_blocked), -) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - -endSection() ?> diff --git a/app/Views/admin/episode/embeddable_player.php b/app/Views/admin/episode/embeddable_player.php deleted file mode 100644 index bb42a4a3..00000000 --- a/app/Views/admin/episode/embeddable_player.php +++ /dev/null @@ -1,65 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - - - -
- $theme): ?> - - -
- - - -
- 'iframe', - 'name' => 'iframe', - 'class' => 'form-textarea w-full h-20 mr-2', - ], - "", - ) ?> - 'default'], - ['data-type' => 'clipboard-copy', 'data-clipboard-target' => 'iframe'], - ) ?> -
- -
- 'url', - 'name' => 'url', - 'class' => 'form-textarea w-full h-10 mr-2', - ], - $episode->embeddable_player_url, - ) ?> - 'default'], - ['data-type' => 'clipboard-copy', 'data-clipboard-target' => 'url'], - ) ?> -
- -endSection() ?> diff --git a/app/Views/admin/episode/list.php b/app/Views/admin/episode/list.php deleted file mode 100644 index d0f455d3..00000000 --- a/app/Views/admin/episode/list.php +++ /dev/null @@ -1,130 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - (getDetails()[ - 'total' - ] ?>) -endSection() ?> - -section('headerRight') ?> -id), [ - 'variant' => 'accent', - 'iconLeft' => 'add', -]) ?> -endSection() ?> - - -section('content') ?> - -

$pager->getDetails()['currentPage'], - 'pageCount' => $pager->getDetails()['pageCount'], -]) ?>

-
- - - - - -

- -
- -links() ?> - -endSection() ?> diff --git a/app/Views/admin/episode/persons.php b/app/Views/admin/episode/persons.php deleted file mode 100644 index 293129f5..00000000 --- a/app/Views/admin/episode/persons.php +++ /dev/null @@ -1,134 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - (persons) ?>) -endSection() ?> - -section('headerRight') ?> - 'primary', 'iconLeft' => 'add'], - ['class' => 'mr-2'], -) ?> -endSection() ?> - -section('content') ?> - -id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - - - lang('Person.episode_form.person'), - 'cell' => function ($person) { - return '
' . - 'image->thumbnail_url}\" alt=\"{$person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" />" . - '
' . - $person->full_name . - implode( - '', - array_map(function ($role) { - return '' . - lang( - "PersonsTaxonomy.persons.{$role->group}.label", - ) . - ' › ' . - lang( - "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", - ) . - ''; - }, $person->roles), - ) . - ($person->information_url === null - ? '' - : "information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" . - $person->information_url . - '') . - '
'; - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($person): string { - return button( - lang('Person.episode_form.remove'), - route_to( - 'episode-person-remove', - $person->podcast_id, - $person->episode_id, - $person->id, - ), - [ - 'variant' => 'danger', - 'size' => 'small', - ], - ); - }, - ], - ], - $episode->persons, -) ?> - - - - - - - - 'persons', - 'class' => 'form-select mb-4', - 'required' => 'required', -]) ?> - - - 'roles', 'class' => 'form-select mb-4'], -) ?> - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - -endSection() ?> diff --git a/app/Views/admin/episode/publish.php b/app/Views/admin/episode/publish.php deleted file mode 100644 index e1ed34bc..00000000 --- a/app/Views/admin/episode/publish.php +++ /dev/null @@ -1,179 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id, $episode->id), - icon('arrow-left', 'mr-2 text-lg') . lang('Episode.publish_form.back_to_episode_dashboard'), - ['class' => 'inline-flex items-center font-semibold mr-4 text-sm'], -) ?> - -id, $episode->id), [ - 'method' => 'post', - 'class' => 'mx-auto flex flex-col max-w-xl items-start', - 'data-submit' => 'validate-message' -]) ?> - - - - - - -
-
- <?= $podcast
-                                                                        ->actor->display_name ?> -

- actor - ->display_name ?> - @actor - ->username ?> -

-
-
- 'message', - 'name' => 'message', - 'class' => 'form-textarea min-w-0 w-full', - 'placeholder' => 'Write your message...', - 'autofocus' => '' - ], - old('message', '', false), - ['rows' => 2], - ) ?> -
- -
- - - -
-
- - 'flex flex-col mb-4']) ?> - - -
- 'schedule', - 'name' => 'publication_method', - 'class' => 'text-pine-700', - ], - 'schedule', - old('publication_method') && - old('publication_method') === 'schedule', - ) ?> - -
- -
- 'scheduled_publication_date', - 'name' => 'scheduled_publication_date', - 'class' => 'form-input rounded-r-none flex-1', - 'value' => old('scheduled_publication_date', ''), - 'data-input' => '', - ]) ?> - -
-
-
- - - - - 'primary'], - [ - 'class' => 'self-end mt-4', - 'type' => 'submit', - 'data-btn-text-warning' => lang('Episode.publish_form.message_warning_submit'), - 'data-btn-text' => lang('Episode.publish_form.submit_edit') - ], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/episode/publish_edit.php b/app/Views/admin/episode/publish_edit.php deleted file mode 100644 index 52e23326..00000000 --- a/app/Views/admin/episode/publish_edit.php +++ /dev/null @@ -1,210 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id, $episode->id), - icon('arrow-left', 'mr-2 text-lg') . lang('Episode.publish_form.back_to_episode_dashboard'), - ['class' => 'inline-flex items-center font-semibold mr-4 text-sm'], -) ?> - -id, $episode->id), [ - 'method' => 'post', - 'class' => 'mx-auto flex flex-col max-w-xl items-start', - 'data-submit' => 'validate-message' -]) ?> - - -id) ?> - - - - -
-
- <?= $podcast->actor
-                                                                        ->display_name ?> -
-

- actor - ->display_name ?> - @actor->username ?> -

- -
-
-
- 'message', - 'name' => 'message', - 'class' => 'form-textarea', - 'placeholder' => 'Write your message...', - 'autofocus' => '' - ], - old('message', $status->message, false), - ['rows' => 2], - ) ?> -
- -
- - - -
-
- - 'flex flex-col mb-4']) ?> - - -
- 'schedule', - 'name' => 'publication_method', - 'class' => 'text-pine-700', - ], - 'schedule', - old('publication_method') - ? old('publication_method') === 'schedule' - : true, - ) ?> - -
- -
- 'scheduled_publication_date', - 'name' => 'scheduled_publication_date', - 'class' => 'form-input rounded-r-none flex-1', - 'value' => old( - 'scheduled_publication_date', - $episode->published_at, - ), - 'data-input' => '', - ]) ?> - -
-
-
- - - - -
- id, $episode->id), - lang('Episode.publish_form.cancel_publication'), - ['class' => 'py-2 px-3 rounded-full bg-red-100 text-red-900 font-semibold mr-4'], - ) ?> - - 'primary'], - [ - 'type' => 'submit', - 'data-btn-text-warning' => lang('Episode.publish_form.message_warning_submit'), - 'data-btn-text' => lang('Episode.publish_form.submit_edit') - ], - ) ?> -
- - - -endSection() ?> \ No newline at end of file diff --git a/app/Views/admin/episode/soundbites.php b/app/Views/admin/episode/soundbites.php deleted file mode 100644 index dc1c2362..00000000 --- a/app/Views/admin/episode/soundbites.php +++ /dev/null @@ -1,209 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id, $episode->id), - ['method' => 'post', 'class' => 'flex flex-col'], -) ?> - - - - - - - - - - - - - - - soundbites as $soundbite): ?> - - - - - - - - - - - - - - - -
-
'number', - 'min' => 0, - 'max' => $episode->audio_file_duration, - 'step' => 'any', - 'id' => "soundbites[{$soundbite->id}][start_time]", - 'name' => "soundbites[{$soundbite->id}][start_time]", - 'class' => 'form-input w-full border-none text-center', - 'value' => $soundbite->start_time, - 'data-type' => 'soundbite-field', - 'data-field-type' => 'start-time', - 'data-soundbite-id' => $soundbite->id, - 'required' => 'required', - ], - ) ?> 'number', - 'min' => 0, - 'max' => $episode->audio_file_duration, - 'step' => 'any', - 'id' => "soundbites[{$soundbite->id}][duration]", - 'name' => "soundbites[{$soundbite->id}][duration]", - 'class' => 'form-input w-full border-none text-center', - 'value' => $soundbite->duration, - 'data-type' => 'soundbite-field', - 'data-field-type' => 'duration', - 'data-soundbite-id' => $soundbite->id, - 'required' => 'required', - ], - ) ?> "soundbites[{$soundbite->id}][label]", - 'name' => "soundbites[{$soundbite->id}][label]", - 'class' => 'form-input w-full border-none', - 'value' => $soundbite->label, - ], - ) ?> 'primary'], - [ - 'class' => 'mb-1 mr-1', - 'data-type' => 'play-soundbite', - 'data-soundbite-id' => $soundbite->id, - 'data-soundbite-start-time' => $soundbite->start_time, - 'data-soundbite-duration' => $soundbite->duration, - ], - ) ?> - id, - $episode->id, - $soundbite->id, - ), - ['variant' => 'danger'], - [], - ) ?> -
'number', - 'min' => 0, - 'max' => $episode->audio_file_duration, - 'step' => 'any', - 'id' => 'soundbites[0][start_time]', - 'name' => 'soundbites[0][start_time]', - 'class' => 'form-input w-full border-none text-center', - 'value' => old('start_time'), - 'data-soundbite-id' => '0', - 'data-type' => 'soundbite-field', - 'data-field-type' => 'start-time', - ], - ) ?> 'number', - 'min' => 0, - 'max' => $episode->audio_file_duration, - 'step' => 'any', - 'id' => 'soundbites[0][duration]', - 'name' => 'soundbites[0][duration]', - 'class' => 'form-input w-full border-none text-center', - 'value' => old('duration'), - 'data-soundbite-id' => '0', - 'data-type' => 'soundbite-field', - 'data-field-type' => 'duration', - ], - ) ?> 'soundbites[0][label]', - 'name' => 'soundbites[0][label]', - 'class' => 'form-input w-full border-none', - 'value' => old('label'), - ], - ) ?> 'primary'], - [ - 'data-type' => 'play-soundbite', - 'data-soundbite-id' => 0, - 'data-soundbite-start-time' => 0, - 'data-soundbite-duration' => 0, - ], - ) ?> - - -
- - 'info'], - [ - 'data-type' => 'get-soundbite', - 'data-start-time-field-name' => 'soundbites[0][start_time]', - 'data-duration-field-name' => 'soundbites[0][duration]', - ], - ) ?>
- - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - -endSection() ?> diff --git a/app/Views/admin/episode/unpublish.php b/app/Views/admin/episode/unpublish.php deleted file mode 100644 index 64f1c465..00000000 --- a/app/Views/admin/episode/unpublish.php +++ /dev/null @@ -1,53 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - -id, $episode->id), [ - 'class' => 'flex flex-col max-w-xl mx-auto', -]) ?> - -

- - - -
-id, $episode->id), -) ?> - - 'danger'], - ['type' => 'submit'], -) ?> -
- - - - -endSection() ?> diff --git a/app/Views/admin/episode/view.php b/app/Views/admin/episode/view.php deleted file mode 100644 index 38b257b4..00000000 --- a/app/Views/admin/episode/view.php +++ /dev/null @@ -1,155 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('headerLeft') ?> -published_at, - $episode->publication_status, - 'text-sm ml-2 align-middle', -) ?> -endSection() ?> - -section('headerRight') ?> -id, - $episode->id, - $episode->publication_status, -) ?> -endSection() ?> - - -section('content') ?> - -
-
- Episode cover - - -
- id, $episode->id), - ['variant' => 'info', 'iconLeft' => 'edit'], - ) ?> - name, $episode->slug), - ['variant' => 'secondary', 'iconLeft' => 'external-link'], - ) ?> - id, $episode->id), - ['variant' => 'danger', 'iconLeft' => 'delete-bin'], - ) ?> -
-
- -
- location, 'text-sm') ?> - description_html ?> -
-
- -
- id, $episode->id), - ['variant' => 'info', 'iconLeft' => 'movie'], - ['class' => 'mb-4'], - ) ?> - id, $episode->id), - ['variant' => 'info', 'iconLeft' => 'edit'], - ['class' => 'mb-4'], - ) ?> - id, $episode->id), - ['variant' => 'info', 'iconLeft' => 'folder-user'], - ['class' => 'mb-4'], - ) ?> - soundbites) > 0): ?> - 'Play', - 'cell' => function ($soundbite): string { - return icon_button( - 'play', - lang('Episode.soundbites_form.play'), - '', - ['variant' => 'primary'], - [ - 'class' => 'mb-1 mr-1', - 'data-type' => 'play-soundbite', - 'data-soundbite-start-time' => - $soundbite->start_time, - 'data-soundbite-duration' => $soundbite->duration, - ], - ); - }, - ], - [ - 'header' => lang('Episode.soundbites_form.start_time'), - 'cell' => function ($soundbite): string { - return format_duration($soundbite->start_time); - }, - ], - [ - 'header' => lang('Episode.soundbites_form.duration'), - 'cell' => function ($soundbite): string { - return format_duration($soundbite->duration); - }, - ], - [ - 'header' => lang('Episode.soundbites_form.label'), - 'cell' => function ($soundbite) { - return $soundbite->label; - }, - ], - ], - $episode->soundbites, - ) ?> - -
- -
-

-
-
- -
-

-
-
- - -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/fediverse/blocked_actors.php b/app/Views/admin/fediverse/blocked_actors.php deleted file mode 100644 index 0cc8ba5a..00000000 --- a/app/Views/admin/fediverse/blocked_actors.php +++ /dev/null @@ -1,83 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'post', - 'class' => 'flex flex-col max-w-md mb-8', -]) ?> - - - 'handle', - 'name' => 'handle', - 'class' => 'form-input mb-4', - 'type' => 'text', - ], - old('handle', ''), -) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - - lang('Fediverse.list.actor'), - 'cell' => function ($blockedActor) { - return $blockedActor->username; - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($blockedActor) { - return '
' . - '' . - csrf_field() . - button( - lang('Fediverse.list.unblock'), - route_to( - 'fediverse-unblock-actor', - $blockedActor->username, - ), - ['variant' => 'info', 'size' => 'small'], - [ - 'class' => 'mr-2', - 'type' => 'submit', - ], - ) . - '
'; - }, - ], - ], - $blockedActors, -) ?> - - -endSection() ?> diff --git a/app/Views/admin/fediverse/blocked_domains.php b/app/Views/admin/fediverse/blocked_domains.php deleted file mode 100644 index 713b737b..00000000 --- a/app/Views/admin/fediverse/blocked_domains.php +++ /dev/null @@ -1,80 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'post', - 'class' => 'flex flex-col max-w-md mb-8', -]) ?> - - - 'domain', - 'name' => 'domain', - 'class' => 'form-input mb-4', - 'type' => 'text', - ], - old('domain', ''), -) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - lang('Fediverse.list.actor'), - 'cell' => function ($blockedDomain) { - return $blockedDomain->name; - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($blockedDomain) { - return '
' . - '' . - csrf_field() . - button( - lang('Fediverse.list.unblock'), - route_to( - 'fediverse-unblock-domain', - $blockedDomain->name, - ), - ['variant' => 'info', 'size' => 'small'], - [ - 'class' => 'mr-2', - 'type' => 'submit', - ], - ) . - '
'; - }, - ], - ], - $blockedDomains, -) ?> - -endSection() ?> diff --git a/app/Views/admin/my_account/change_password.php b/app/Views/admin/my_account/change_password.php deleted file mode 100644 index 6af3e6d5..00000000 --- a/app/Views/admin/my_account/change_password.php +++ /dev/null @@ -1,48 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'flex flex-col max-w-sm', -]) ?> - - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'password', -]) ?> - - - 'new_password', - 'name' => 'new_password', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'password', - - 'autocomplete' => 'new-password', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/my_account/view.php b/app/Views/admin/my_account/view.php deleted file mode 100644 index 77d30922..00000000 --- a/app/Views/admin/my_account/view.php +++ /dev/null @@ -1,16 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - user()]) ?> - -endSection() ?> diff --git a/app/Views/admin/page/create.php b/app/Views/admin/page/create.php deleted file mode 100644 index 94b00916..00000000 --- a/app/Views/admin/page/create.php +++ /dev/null @@ -1,63 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'flex flex-col max-w-3xl', -]) ?> - - - 'max-w-sm']) ?> - 'title', - 'name' => 'title', - 'class' => 'form-input mb-4 max-w-sm', - 'value' => old('title'), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - 'max-w-sm']) ?> - 'slug', - 'name' => 'slug', - 'class' => 'form-input mb-4 max-w-sm', - 'value' => old('slug'), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - -
- - 'content', - 'name' => 'content', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('content', '', false), - 'data-editor="markdown"', - ) ?> -
- - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/page/edit.php b/app/Views/admin/page/edit.php deleted file mode 100644 index 3fee95ad..00000000 --- a/app/Views/admin/page/edit.php +++ /dev/null @@ -1,62 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id), [ - 'class' => 'flex flex-col max-w-3xl', -]) ?> - - - 'max-w-sm']) ?> - 'title', - 'name' => 'title', - 'class' => 'form-input mb-4 max-w-sm', - 'value' => old('title', $page->title), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - 'max-w-sm']) ?> - 'slug', - 'name' => 'slug', - 'class' => 'form-input mb-4 max-w-sm', - 'value' => old('slug', $page->slug), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - -
- - 'content', - 'name' => 'content', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('content', $page->content_markdown, false), - 'data-editor="markdown"', - ) ?> -
- - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/page/list.php b/app/Views/admin/page/list.php deleted file mode 100644 index 2a113a21..00000000 --- a/app/Views/admin/page/list.php +++ /dev/null @@ -1,62 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - () -endSection() ?> - -section('headerRight') ?> - 'accent', - 'iconLeft' => 'add', -]) ?> -endSection() ?> - - -section('content') ?> - - lang('Page.page'), - 'cell' => function ($page) { - return '
' . - $page->title . - '/' . - $page->slug . - '
'; - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($page) { - return button( - lang('Page.go_to_page'), - route_to('page', $page->slug), - [ - 'variant' => 'secondary', - 'size' => 'small', - ], - ['class' => 'mr-2'], - ) . - button( - lang('Page.edit'), - route_to('page-edit', $page->id), - ['variant' => 'info', 'size' => 'small'], - ['class' => 'mr-2'], - ) . - button( - lang('Page.delete'), - route_to('page-delete', $page->id), - ['variant' => 'danger', 'size' => 'small'], - ); - }, - ], - ], - $pages, -) ?> - -endSection() ?> diff --git a/app/Views/admin/page/view.php b/app/Views/admin/page/view.php deleted file mode 100644 index 029b9587..00000000 --- a/app/Views/admin/page/view.php +++ /dev/null @@ -1,22 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('headerRight') ?> -id), [ - 'variant' => 'accent', - 'iconLeft' => 'add', -]) ?> -endSection() ?> - -section('content') ?> -
- content_html ?> -
-endSection() ?> diff --git a/app/Views/admin/person/create.php b/app/Views/admin/person/create.php deleted file mode 100644 index b89ae188..00000000 --- a/app/Views/admin/person/create.php +++ /dev/null @@ -1,95 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - - 'full_name', - 'name' => 'full_name', - 'class' => 'form-input mb-4', - 'value' => old('full_name'), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - - 'unique_name', - 'name' => 'unique_name', - 'class' => 'form-input mb-4', - 'value' => old('unique_name'), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - - - 'information_url', - 'name' => 'information_url', - 'class' => 'form-input mb-4', - 'value' => old('information_url'), -]) ?> - - - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'required' => 'required', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - - -endSection() ?> diff --git a/app/Views/admin/person/edit.php b/app/Views/admin/person/edit.php deleted file mode 100644 index c76f3c54..00000000 --- a/app/Views/admin/person/edit.php +++ /dev/null @@ -1,95 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - -id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - -image->thumbnail_url}\" alt=\"{$person->full_name}\" class=\"object-cover w-32 h-32 mt-3 rounded\" />", -) ?> - - - 'full_name', - 'name' => 'full_name', - 'class' => 'form-input mb-4', - 'value' => old('full_name', $person->full_name), - 'required' => 'required', - 'data-slugify' => 'title', -]) ?> - - - 'unique_name', - 'name' => 'unique_name', - 'class' => 'form-input mb-4', - 'value' => old('unique_name', $person->unique_name), - 'required' => 'required', - 'data-slugify' => 'slug', -]) ?> - - - 'information_url', - 'name' => 'information_url', - 'class' => 'form-input mb-4', - 'value' => old('information_url', $person->information_url), -]) ?> - - - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - - -endSection() ?> diff --git a/app/Views/admin/person/list.php b/app/Views/admin/person/list.php deleted file mode 100644 index d093e482..00000000 --- a/app/Views/admin/person/list.php +++ /dev/null @@ -1,65 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - () -endSection() ?> - -section('headerRight') ?> - 'primary', 'iconLeft' => 'add'], - ['class' => 'mr-2'], -) ?> -endSection() ?> - -section('content') ?> - -
- - - - - -

- -
- -endSection() ?> diff --git a/app/Views/admin/person/view.php b/app/Views/admin/person/view.php deleted file mode 100644 index 21916064..00000000 --- a/app/Views/admin/person/view.php +++ /dev/null @@ -1,38 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -full_name ?> -endSection() ?> - -section('pageTitle') ?> -full_name ?> - -endSection() ?> - -section('headerRight') ?> -id), - ['variant' => 'secondary', 'iconLeft' => 'edit'], - ['class' => 'mr-2'], -) ?> -endSection() ?> - -section('content') ?> - -
-
- $person->full_name -
- -
- full_name ?>
- information_url ?> -
-
- -endSection() ?> diff --git a/app/Views/admin/podcast/_sidebar.php b/app/Views/admin/podcast/_sidebar.php deleted file mode 100644 index 5cf21393..00000000 --- a/app/Views/admin/podcast/_sidebar.php +++ /dev/null @@ -1,119 +0,0 @@ - [ - 'icon' => 'dashboard', - 'items' => ['podcast-view', 'podcast-edit'], - ], - 'episodes' => [ - 'icon' => 'mic', - 'items' => ['episode-list', 'episode-create'], - ], - 'persons' => [ - 'icon' => 'folder-user', - 'items' => ['podcast-person-manage'], - ], - 'analytics' => [ - 'icon' => 'line-chart', - 'items' => [ - 'podcast-analytics', - 'podcast-analytics-unique-listeners', - 'podcast-analytics-listening-time', - 'podcast-analytics-players', - 'podcast-analytics-locations', - 'podcast-analytics-time-periods', - 'podcast-analytics-webpages', - ], - ], - 'contributors' => [ - 'icon' => 'group', - 'items' => ['contributor-list', 'contributor-add'], - ], - 'platforms' => [ - 'icon' => 'link', - 'items' => [ - 'platforms-podcasting', - 'platforms-social', - 'platforms-funding', - ], - ], -]; ?> - - - - - - -
- <?= $podcast->title ?> -
- title ?> - @name ?> - - -
-
- - - - diff --git a/app/Views/admin/podcast/analytics/index.php b/app/Views/admin/podcast/analytics/index.php deleted file mode 100644 index 0d691f9a..00000000 --- a/app/Views/admin/podcast/analytics/index.php +++ /dev/null @@ -1,43 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> -
-

-
-
- -
-

-
-
- -
-

-
-
- -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/listening_time.php b/app/Views/admin/podcast/analytics/listening_time.php deleted file mode 100644 index 98a7fd4b..00000000 --- a/app/Views/admin/podcast/analytics/listening_time.php +++ /dev/null @@ -1,34 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
-

-
-
- -
-

-
-
- -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/locations.php b/app/Views/admin/podcast/analytics/locations.php deleted file mode 100644 index d2164889..00000000 --- a/app/Views/admin/podcast/analytics/locations.php +++ /dev/null @@ -1,46 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
-
-

-
-
- -
-

-
-
-
- -
-

-
-
- - -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/players.php b/app/Views/admin/podcast/analytics/players.php deleted file mode 100644 index 08c03b43..00000000 --- a/app/Views/admin/podcast/analytics/players.php +++ /dev/null @@ -1,66 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
-
-

-
-
- -
-

-
-
- -
-

-
-
- -
-

-
-
-
- -
-

-
-
- -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/time_periods.php b/app/Views/admin/podcast/analytics/time_periods.php deleted file mode 100644 index 1c8329f1..00000000 --- a/app/Views/admin/podcast/analytics/time_periods.php +++ /dev/null @@ -1,36 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
-
-

-
-
- -
-

-
-
- -
- -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/unique_listeners.php b/app/Views/admin/podcast/analytics/unique_listeners.php deleted file mode 100644 index 279d7652..00000000 --- a/app/Views/admin/podcast/analytics/unique_listeners.php +++ /dev/null @@ -1,34 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
-

-
-
- -
-

-
-
- -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/analytics/webpages.php b/app/Views/admin/podcast/analytics/webpages.php deleted file mode 100644 index 05689f76..00000000 --- a/app/Views/admin/podcast/analytics/webpages.php +++ /dev/null @@ -1,61 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('content') ?> - -
- -
-

-
-
- - -
-

-
-
- - -
-

-
-
- - -
-

-
-
- -
- - - -asset('js/charts.ts', 'js') ?> -endSection() ?> diff --git a/app/Views/admin/podcast/create.php b/app/Views/admin/podcast/create.php deleted file mode 100644 index b4509d94..00000000 --- a/app/Views/admin/podcast/create.php +++ /dev/null @@ -1,392 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'required' => 'required', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - 'title', - 'name' => 'title', - 'class' => 'form-input mb-4', - 'value' => old('title'), - 'required' => 'required', -]) ?> - - - 'name', - 'name' => 'name', - 'class' => 'form-input mb-4', - 'value' => old('name'), - 'required' => 'required', -]) ?> - - 'mb-4']) ?> - - - - 'episodic', 'name' => 'type', 'class' => 'form-radio-btn'], - 'episodic', - old('type') ? old('type') == 'episodic' : true, - ) ?> - - 'serial', 'name' => 'type', 'class' => 'form-radio-btn'], - 'serial', - old('type') && old('type') == 'serial', - ) ?> - - - -
- - 'description', - 'name' => 'description', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('description', '', false), - 'data-editor="markdown"', - ) ?> -
- - - - - - - - 'language', - 'class' => 'form-select mb-4', - 'required' => 'required', -]) ?> - - - 'category', - 'class' => 'form-select mb-4', - 'required' => 'required', - 'placeholder' => lang('Podcast.form.category_placeholder') -]) ?> - - - 'other_categories', - 'class' => 'mb-4', - 'data-max-item-count' => '2', - ], -) ?> - - 'mb-4']) ?> - - - - 'undefined', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'undefined', - old('parental_advisory') - ? old('parental_advisory') === 'undefined' - : true, - ) ?> - - 'clean', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'clean', - old('parental_advisory') && old('parental_advisory') === 'clean', - ) ?> - - 'explicit', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'explicit', - old('parental_advisory') && old('parental_advisory') === 'explicit', - ) ?> - - - - - - - - - - 'owner_name', - 'name' => 'owner_name', - 'class' => 'form-input mb-4', - 'value' => old('owner_name'), - 'required' => 'required', -]) ?> - - - 'owner_email', - 'name' => 'owner_email', - 'class' => 'form-input mb-4', - 'value' => old('owner_email'), - 'type' => 'email', - 'required' => 'required', -]) ?> - - - 'publisher', - 'name' => 'publisher', - 'class' => 'form-input mb-4', - 'value' => old('publisher'), -]) ?> - - - 'copyright', - 'name' => 'copyright', - 'class' => 'form-input mb-4', - 'value' => old('copyright'), -]) ?> - - - - - - - 'location_name', - 'name' => 'location_name', - 'class' => 'form-input mb-4', - 'value' => old('location_name'), -]) ?> - - - - - - 'payment_pointer', - 'name' => 'payment_pointer', - 'class' => 'form-input mb-4', - 'value' => old('payment_pointer'), -]) ?> - - -
-
- - 'partner_id', - 'name' => 'partner_id', - 'class' => 'form-input w-full', - 'value' => old('partner_id'), - ]) ?> -
-
- - 'partner_link_url', - 'name' => 'partner_link_url', - 'class' => 'form-input w-full', - 'value' => old('partner_link_url'), - ]) ?> -
-
- - 'partner_image_url', - 'name' => 'partner_image_url', - 'class' => 'form-input w-full', - 'value' => old('partner_image_url'), - ]) ?> -
-
- - - - - - 'custom_rss', - 'name' => 'custom_rss', - 'class' => 'form-textarea', - 'value' => old('custom_rss'), -]) ?> - - - - - 'block', 'name' => 'block'], - 'yes', - old('block', false), - 'mb-2', -) ?> - - 'complete', 'name' => 'complete'], - 'yes', - old('complete', false), - 'mb-2', -) ?> - - 'lock', 'name' => 'lock'], - 'yes', - old('lock', true), -) ?> - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - - -endSection() ?> diff --git a/app/Views/admin/podcast/edit.php b/app/Views/admin/podcast/edit.php deleted file mode 100644 index c0ca9e64..00000000 --- a/app/Views/admin/podcast/edit.php +++ /dev/null @@ -1,390 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - -id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - -<?= $podcast->title ?> - 'image', - 'name' => 'image', - 'class' => 'form-input', - 'type' => 'file', - 'accept' => '.jpg,.jpeg,.png', -]) ?> - - - - 'title', - 'name' => 'title', - 'class' => 'form-input mb-1', - 'value' => old('title', $podcast->title), - 'required' => 'required', -]) ?> -link ?> - - 'mb-4']) ?> - - - 'episodic', 'name' => 'type', 'class' => 'form-radio-btn'], - 'episodic', - old('type') ? old('type') == 'episodic' : $podcast->type == 'episodic', - ) ?> - - 'serial', 'name' => 'type', 'class' => 'form-radio-btn'], - 'serial', - old('type') ? old('type') == 'serial' : $podcast->type == 'serial', - ) ?> - - - -
- - 'description', - 'name' => 'description', - 'class' => 'form-textarea', - 'required' => 'required', - ], - old('description', $podcast->description_markdown, false), - 'data-editor="markdown"', - ) ?> -
- - - - - - - -language_code), - [ - 'id' => 'language', - 'class' => 'form-select mb-4', - 'required' => 'required', - ], -) ?> - - -category_id), - [ - 'id' => 'category', - 'class' => 'form-select mb-4', - 'required' => 'required', - ], -) ?> - - -other_categories_ids), - [ - 'id' => 'other_categories', - 'class' => 'mb-4', - 'data-max-item-count' => '2', - ], -) ?> - - 'mb-4']) ?> - - - 'undefined', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'undefined', - old('parental_advisory') - ? old('parental_advisory') === 'undefined' - : $podcast->parental_advisory === null, - ) ?> - - 'clean', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'clean', - old('parental_advisory') - ? old('parental_advisory') === 'clean' - : $podcast->parental_advisory === 'clean', - ) ?> - - 'explicit', - 'name' => 'parental_advisory', - 'class' => 'form-radio-btn', - ], - 'explicit', - old('parental_advisory') - ? old('parental_advisory') === 'explicit' - : $podcast->parental_advisory === 'explicit', - ) ?> - - - - - - - - - 'owner_name', - 'name' => 'owner_name', - 'class' => 'form-input mb-4', - 'value' => old('owner_name', $podcast->owner_name), - 'required' => 'required', -]) ?> - - - 'owner_email', - 'name' => 'owner_email', - 'class' => 'form-input mb-4', - 'value' => old('owner_email', $podcast->owner_email), - 'type' => 'email', - 'required' => 'required', -]) ?> - - - 'publisher', - 'name' => 'publisher', - 'class' => 'form-input mb-4', - 'value' => old('publisher', $podcast->publisher), -]) ?> - - - 'copyright', - 'name' => 'copyright', - 'class' => 'form-input mb-4', - 'value' => old('copyright', $podcast->copyright), -]) ?> - - - - - - - 'location_name', - 'name' => 'location_name', - 'class' => 'form-input mb-4', - 'value' => old('location_name', $podcast->location_name), -]) ?> - - - - - - 'payment_pointer', - 'name' => 'payment_pointer', - 'class' => 'form-input mb-4', - 'value' => old('payment_pointer', $podcast->payment_pointer), -]) ?> - - -
-
- - 'partner_id', - 'name' => 'partner_id', - 'class' => 'form-input w-full', - 'value' => old('partner_id', $podcast->partner_id), - ]) ?> -
-
- - 'partner_link_url', - 'name' => 'partner_link_url', - 'class' => 'form-input w-full', - 'value' => old('partner_link_url', $podcast->partner_link_url), - ]) ?> -
-
- - 'partner_image_url', - 'name' => 'partner_image_url', - 'class' => 'form-input w-full', - 'value' => old('partner_image_url', $podcast->partner_image_url), - ]) ?> -
-
- - - - - 'custom_rss', - 'name' => 'custom_rss', - 'class' => 'form-textarea', - 'value' => old('custom_rss', $podcast->custom_rss_string), -]) ?> - - - - - 'block', 'name' => 'block'], - 'yes', - old('block', $podcast->is_blocked), - 'mb-2', -) ?> - - 'complete', 'name' => 'complete'], - 'yes', - old('complete', $podcast->is_completed), - 'mb-2', -) ?> - - 'lock', 'name' => 'lock'], - 'yes', - old('lock', $podcast->is_locked), -) ?> - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - -endSection() ?> diff --git a/app/Views/admin/podcast/import.php b/app/Views/admin/podcast/import.php deleted file mode 100644 index bec1dd32..00000000 --- a/app/Views/admin/podcast/import.php +++ /dev/null @@ -1,228 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - - 'post', - 'class' => 'flex flex-col items-start', -]) ?> - - - - - - - - 'imported_feed_url', - 'name' => 'imported_feed_url', - 'class' => 'form-input', - 'value' => old('imported_feed_url'), - 'placeholder' => 'https://...', - 'type' => 'url', - 'required' => 'required', -]) ?> - - - - - - - - 'name', - 'name' => 'name', - 'class' => 'form-input mb-4', - 'value' => old('name'), - 'required' => 'required', -]) ?> - - - 'language', - 'class' => 'form-select mb-4', - 'required' => 'required', -]) ?> - - - 'category', - 'class' => 'form-select mb-4', - 'required' => 'required', - 'placeholder' => lang('Podcast.form.category_placeholder') -]) ?> - - - - - - - 'flex flex-col mb-4']) ?> - - - - - - 'flex flex-col mb-4']) ?> - - - - - - - - - - - - 'season_number', - 'name' => 'season_number', - 'class' => 'form-input mb-4', - 'value' => old('season_number'), - 'type' => 'number', -]) ?> - - - 'max_episodes', - 'name' => 'max_episodes', - 'class' => 'form-input mb-4', - 'value' => old('max_episodes'), - 'type' => 'number', -]) ?> - - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - - -endSection() ?> diff --git a/app/Views/admin/podcast/latest_episodes.php b/app/Views/admin/podcast/latest_episodes.php deleted file mode 100644 index b36ba213..00000000 --- a/app/Views/admin/podcast/latest_episodes.php +++ /dev/null @@ -1,103 +0,0 @@ -
-
-

- - - - -
- -
- -
- <?= $episode->title ?> -
-
- title ?> - -
- number, - $episode->season_number, - 'font-semibold text-gray-600', - true, - ) ?> - published_at): ?> - - - -
-
- - -
-
- -
- -

- -
\ No newline at end of file diff --git a/app/Views/admin/podcast/list.php b/app/Views/admin/podcast/list.php deleted file mode 100644 index d6f7af28..00000000 --- a/app/Views/admin/podcast/list.php +++ /dev/null @@ -1,63 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - () -endSection() ?> - -section('headerRight') ?> - 'accent', 'iconLeft' => 'add'], - ['class' => 'mr-2'], -) ?> - 'primary', - 'iconLeft' => 'download', -]) ?> -endSection() ?> - - -section('content') ?> - -
- - - - - -

- -
- -endSection() ?> diff --git a/app/Views/admin/podcast/persons.php b/app/Views/admin/podcast/persons.php deleted file mode 100644 index 506cedfe..00000000 --- a/app/Views/admin/podcast/persons.php +++ /dev/null @@ -1,129 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - (persons) ?>) -endSection() ?> - -section('headerRight') ?> - 'primary', 'iconLeft' => 'add'], - ['class' => 'mr-2'], -) ?> -endSection() ?> - -section('content') ?> - -id), [ - 'method' => 'post', - 'class' => 'flex flex-col', -]) ?> - - - - - - lang('Person.podcast_form.person'), - 'cell' => function ($person) { - return '
' . - 'image->thumbnail_url}\" alt=\"{$person->full_name}\" class=\"object-cover w-16 h-16 rounded-full\" />" . - '
' . - $person->full_name . - implode( - '', - array_map(function ($role) { - return '' . - lang( - "PersonsTaxonomy.persons.{$role->group}.label", - ) . - ' › ' . - lang( - "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", - ) . - ''; - }, $person->roles), - ) . - ($person->information_url === null - ? '' - : "information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" . - $person->information_url . - '') . - '
'; - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($person): string { - return button( - lang('Person.podcast_form.remove'), - route_to( - 'podcast-person-remove', - $person->podcast_id, - $person->id, - ), - [ - 'variant' => 'danger', - 'size' => 'small', - ], - ); - }, - ], - ], - $podcast->persons, -) ?> - - - - - - - - 'persons', - 'class' => 'form-select mb-4', - 'required' => 'required', -]) ?> - - - 'roles', - 'class' => 'form-select mb-4', -]) ?> - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - -endSection() ?> diff --git a/app/Views/admin/podcast/platforms.php b/app/Views/admin/podcast/platforms.php deleted file mode 100644 index 6cd06182..00000000 --- a/app/Views/admin/podcast/platforms.php +++ /dev/null @@ -1,149 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> - -id, $platformType), [ - 'class' => 'flex flex-col max-w-md', -]) ?> - - - - -
-
- submit_url, - icon( - $platform->type . '/' . $platform->slug, - 'text-gray-600 text-4xl', - ), - [ - 'class' => 'mb-1 text-gray-600 hover:text-gray-900', - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang('Platforms.submit_url', [ - 'platformName' => $platform->label, - ]), - ], - ) ?> -
- home_url, icon('external-link', 'mx-auto'), [ - 'class' => 'flex-1 text-gray-600 hover:text-gray-900', - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang('Platforms.home_url', [ - 'platformName' => $platform->label, - ]), - ]) ?> - submit_url - ? anchor($platform->submit_url, icon('add', 'mx-auto'), [ - 'class' => 'flex-1 text-gray-600 hover:text-gray-900', - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang('Platforms.submit_url', [ - 'platformName' => $platform->label, - ]), - ]) - : '' ?> -
-
-
- link_url - ? anchor( - route_to( - 'podcast-platform-remove', - $podcast->id, - $platform->slug, - ), - icon('delete-bin', 'mx-auto'), - [ - 'class' => - 'absolute right-0 p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900', - 'data-toggle' => 'tooltip', - 'data-placement' => 'bottom', - 'title' => lang('Platforms.remove', [ - 'platformName' => $platform->label, - ]), - ], - ) - : '' ?> - label, $platform->slug, [ - 'class' => 'font-semibold mb-2', - ]) ?> - $platform->slug . '_link_url', - 'name' => 'platforms[' . $platform->slug . '][url]', - 'class' => 'form-input mb-1 w-full', - 'value' => old($platform->slug . '_link_url', $platform->link_url), - 'type' => 'url', - 'placeholder' => 'https://...', - ]) ?> - $platform->slug . '_link_content', - 'name' => 'platforms[' . $platform->slug . '][content]', - 'class' => 'form-input mb-1 w-full', - 'value' => old( - $platform->slug . '_link_content', - $platform->link_content, - ), - 'type' => 'text', - 'placeholder' => lang("Platforms.description.{$platform->type}"), - ]) ?> - $platform->slug . '_visible', - 'name' => 'platforms[' . $platform->slug . '][visible]', - ], - 'yes', - old( - $platform->slug . '_visible', - $platform->is_visible ? $platform->is_visible : false, - ), - 'text-sm mb-1', - ) ?> - $platform->slug . '_on_embeddable_player', - 'name' => - 'platforms[' . $platform->slug . '][on_embeddable_player]', - ], - 'yes', - old( - $platform->slug . '_on_embeddable_player', - $platform->is_on_embeddable_player - ? $platform->is_on_embeddable_player - : false, - ), - 'text-sm', - ) ?> -
-
- - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/podcast/settings/dashboard.php b/app/Views/admin/podcast/settings/dashboard.php deleted file mode 100644 index 4b9bfa56..00000000 --- a/app/Views/admin/podcast/settings/dashboard.php +++ /dev/null @@ -1,13 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - -section('content') ?> -Podcast settings... -endSection() ?> diff --git a/app/Views/admin/podcast/view.php b/app/Views/admin/podcast/view.php deleted file mode 100644 index 8bf1c6f0..00000000 --- a/app/Views/admin/podcast/view.php +++ /dev/null @@ -1,35 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> -title ?> -endSection() ?> - -section('pageTitle') ?> -title ?> -endSection() ?> - -section('headerLeft') ?> -location, 'ml-4 text-sm') ?> -endSection() ?> - -section('headerRight') ?> -id), - ['variant' => 'primary', 'iconLeft' => 'edit'], - ['class' => 'mr-2'], -) ?> -id), [ - 'variant' => 'accent', - 'iconLeft' => 'add', -]) ?> -endSection() ?> - -section('content') ?> - - 5, - 'podcast_id' => $podcast->id, -]) ?> - -endSection() ?> diff --git a/app/Views/admin/user/create.php b/app/Views/admin/user/create.php deleted file mode 100644 index afc93cb8..00000000 --- a/app/Views/admin/user/create.php +++ /dev/null @@ -1,52 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - -endSection() ?> - - -section('content') ?> - - 'flex flex-col max-w-sm']) ?> - - - - 'email', - 'name' => 'email', - 'class' => 'form-input mb-4', - 'value' => old('email'), - 'type' => 'email', -]) ?> - - - 'username', - 'name' => 'username', - 'class' => 'form-input mb-4', - 'value' => old('username'), -]) ?> - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'type' => 'password', - 'autocomplete' => 'new-password', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/user/edit.php b/app/Views/admin/user/edit.php deleted file mode 100644 index 4fac32d9..00000000 --- a/app/Views/admin/user/edit.php +++ /dev/null @@ -1,34 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - $user->username]) ?> -endSection() ?> - -section('pageTitle') ?> - $user->username]) ?> -endSection() ?> - - -section('content') ?> - -id), [ - 'class' => 'flex flex-col max-w-sm', -]) ?> - - - -roles, [ - 'id' => 'roles', - 'class' => 'mb-4', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/admin/user/list.php b/app/Views/admin/user/list.php deleted file mode 100644 index a7e34bea..00000000 --- a/app/Views/admin/user/list.php +++ /dev/null @@ -1,88 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - -endSection() ?> - -section('pageTitle') ?> - () -endSection() ?> - -section('headerRight') ?> - 'accent', - 'iconLeft' => 'user-add', -]) ?> -endSection() ?> - - -section('content') ?> - - lang('User.list.user'), - 'cell' => function ($user) { - return '
' . - $user->username . - '' . - $user->email . - '
'; - }, - ], - [ - 'header' => lang('User.list.roles'), - 'cell' => function ($user) { - return implode(',', $user->roles) . - icon_button( - 'edit', - lang('User.edit_roles', [ - 'username' => $user->username, - ]), - route_to('user-edit', $user->id), - ['variant' => 'info'], - ['class' => 'ml-2'], - ); - }, - ], - [ - 'header' => lang('User.list.banned'), - 'cell' => function ($user) { - return $user->isBanned() - ? lang('Common.yes') - : lang('Common.no'); - }, - ], - [ - 'header' => lang('Common.actions'), - 'cell' => function ($user) { - return button( - lang('User.forcePassReset'), - route_to('user-force_pass_reset', $user->id), - [ - 'variant' => 'secondary', - 'size' => 'small', - ], - ['class' => 'mr-2'], - ) . - button( - lang('User.' . ($user->isBanned() ? 'unban' : 'ban')), - route_to( - $user->isBanned() ? 'user-unban' : 'user-ban', - $user->id, - ), - ['variant' => 'warning', 'size' => 'small'], - ['class' => 'mr-2'], - ) . - button( - lang('User.delete'), - route_to('user-delete', $user->id), - ['variant' => 'danger', 'size' => 'small'], - ); - }, - ], - ], - $users, -) ?> - -endSection() ?> diff --git a/app/Views/admin/user/view.php b/app/Views/admin/user/view.php deleted file mode 100644 index 42aa6495..00000000 --- a/app/Views/admin/user/view.php +++ /dev/null @@ -1,12 +0,0 @@ -extend('admin/_layout') ?> - -section('title') ?> - $user->username]) ?> -endSection() ?> - - -section('content') ?> - - $user]) ?> - -endSection() ?> diff --git a/app/Views/auth/_layout.php b/app/Views/auth/_layout.php deleted file mode 100644 index f16abcea..00000000 --- a/app/Views/auth/_layout.php +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - Castopod Auth - - - - asset('styles/index.css', 'css') ?> - - - -
- - - -
-
-

renderSection( - 'title', - ) ?>

- - renderSection('content') ?> -
-
- renderSection('footer') ?> - - 'Castopod', - ]) ?> -
- diff --git a/app/Views/auth/emails/activation.php b/app/Views/auth/emails/activation.php deleted file mode 100644 index 82a2032f..00000000 --- a/app/Views/auth/emails/activation.php +++ /dev/null @@ -1,11 +0,0 @@ -

This is activation email for your account on .

- -

To activate your account use this URL.

- -

Activate account.

- -
- -

If you did not registered on this website, you can safely ignore this email.

diff --git a/app/Views/auth/emails/forgot.php b/app/Views/auth/emails/forgot.php deleted file mode 100644 index f6509c83..00000000 --- a/app/Views/auth/emails/forgot.php +++ /dev/null @@ -1,13 +0,0 @@ -

Someone requested a password reset at this email address for .

- -

To reset the password use this code or URL and follow the instructions.

- -

Your Code:

- -

Visit the Reset Form.

- -
- -

If you did not request a password reset, you can safely ignore this email.

diff --git a/app/Views/auth/forgot.php b/app/Views/auth/forgot.php deleted file mode 100644 index 5f046c51..00000000 --- a/app/Views/auth/forgot.php +++ /dev/null @@ -1,34 +0,0 @@ - -extend($config->viewLayout) ?> - -section('title') ?> - -endSection() ?> - - -section('content') ?> - -

- - 'flex flex-col']) ?> - - - - 'email', - 'name' => 'email', - 'class' => 'form-input mb-4', - 'type' => 'email', - 'required' => 'required', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/auth/login.php b/app/Views/auth/login.php deleted file mode 100644 index 1a6e8108..00000000 --- a/app/Views/auth/login.php +++ /dev/null @@ -1,57 +0,0 @@ - -extend($config->viewLayout) ?> - -section('title') ?> - -endSection() ?> - - -section('content') ?> - - 'flex flex-col']) ?> - - - - 'login', - 'name' => 'login', - 'class' => 'form-input mb-4', - 'required' => 'required', -]) ?> - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'type' => 'password', - 'required' => 'required', -]) ?> - - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> - - -section('footer') ?> - -
- allowRegistration): ?> - - - -
- -endSection() ?> diff --git a/app/Views/auth/register.php b/app/Views/auth/register.php deleted file mode 100644 index cf81efa4..00000000 --- a/app/Views/auth/register.php +++ /dev/null @@ -1,69 +0,0 @@ - -extend($config->viewLayout) ?> - -section('title') ?> - -endSection() ?> - - -section('content') ?> - - 'flex flex-col']) ?> - - - - 'email', - 'name' => 'email', - 'class' => 'form-input', - 'value' => old('email'), - 'type' => 'email', - 'required' => 'required', - 'aria-describedby' => 'emailHelp', -]) ?> - - - - - - 'username', - 'name' => 'username', - 'class' => 'form-input mb-4', - 'value' => old('username'), - 'required' => 'required', -]) ?> - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'type' => 'password', - 'required' => 'required', - 'autocomplete' => 'new-password', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> - - -section('footer') ?> - -

- -

- -endSection() ?> diff --git a/app/Views/auth/reset.php b/app/Views/auth/reset.php deleted file mode 100644 index 429aba78..00000000 --- a/app/Views/auth/reset.php +++ /dev/null @@ -1,54 +0,0 @@ - -extend($config->viewLayout) ?> - -section('title') ?> - -endSection() ?> - - -section('content') ?> - -

- - 'flex flex-col']) ?> - - - - 'token', - 'name' => 'token', - 'class' => 'form-input mb-4', - 'value' => old('token', $token ?? ''), - 'required' => 'required', -]) ?> - - - 'email', - 'name' => 'email', - 'class' => 'form-input mb-4', - 'value' => old('email'), - 'required' => 'required', - 'type' => 'email', -]) ?> - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'type' => 'password', - 'required' => 'required', - 'autocomplete' => 'new-password', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/credits.php b/app/Views/credits.php deleted file mode 100644 index 2fa3c2ae..00000000 --- a/app/Views/credits.php +++ /dev/null @@ -1,51 +0,0 @@ -extend('_layout') ?> - -section('title') ?> - -endSection() ?> - -section('content') ?> - -
- $groups): ?> - -
- - -
- <?= $persons[
-    'full_name'
-] ?> -
- - - - - - -
-
-
- - - - - - - -
- - -
- -endSection(); ?> diff --git a/app/Views/embeddable_player.php b/app/Views/embeddable_player.php deleted file mode 100644 index 64a4c813..00000000 --- a/app/Views/embeddable_player.php +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - <?= $episode->title ?> - - - asset('styles/index.css', 'css') ?> - - - - - <?= $episode->title ?> - - - - diff --git a/app/Views/errors/cli/error_404.php b/app/Views/errors/cli/error_404.php index 456ea3e8..452a86d5 100644 --- a/app/Views/errors/cli/error_404.php +++ b/app/Views/errors/cli/error_404.php @@ -1,5 +1,7 @@ getFile()) . ':' . $exception->getLine(), 'green')); CLI::newLine(); -CLI::write( - 'at ' . - CLI::color( - clean_path($exception->getFile()) . ':' . $exception->getLine(), - 'green', - ), -); -CLI::newLine(); + +$last = $exception; + +while ($prevException = $last->getPrevious()) { + $last = $prevException; + + CLI::write(' Caused by:'); + CLI::write(' [' . $prevException::class . ']', 'red'); + CLI::write(' ' . $prevException->getMessage()); + CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green')); + CLI::newLine(); +} // The backtrace if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { - $backtraces = $exception->getTrace(); + $backtraces = $last->getTrace(); if ($backtraces) { CLI::write('Backtrace:', 'green'); @@ -28,46 +33,31 @@ if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { foreach ($backtraces as $i => $error) { $padFile = ' '; // 4 spaces $padClass = ' '; // 7 spaces - $c = str_pad($i + 1, 3, ' ', STR_PAD_LEFT); + $c = str_pad((string) ($i + 1), 3, ' ', STR_PAD_LEFT); if (isset($error['file'])) { - $filepath = clean_path($error['file']) . ':' . $error['line']; + $fileKey = clean_path($error['file']) . ':' . $error['line']; - CLI::write($c . $padFile . CLI::color($filepath, 'yellow')); + CLI::write($c . $padFile . CLI::color($fileKey, 'yellow')); } else { - CLI::write( - $c . $padFile . CLI::color('[internal function]', 'yellow'), - ); + CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow')); } $function = ''; if (isset($error['class'])) { - $type = - $error['type'] === '->' - ? '()' . $error['type'] - : $error['type']; - $function .= - $padClass . $error['class'] . $type . $error['function']; - } elseif (!isset($error['class']) && isset($error['function'])) { + $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type']; + $function .= $padClass . $error['class'] . $type . $error['function']; + } elseif (! isset($error['class']) && isset($error['function'])) { $function .= $padClass . $error['function']; } - $args = implode( - ', ', - array_map(function ($value) { - switch (true) { - case is_object($value): - return 'Object(' . $value::class . ')'; - case is_array($value): - return count($value) > 0 ? '[...]' : '[]'; - case is_null($value): - return 'null'; // return the lowercased version - default: - return var_export($value, true); - } - }, array_values($error['args'] ?? [])), - ); + $args = implode(', ', array_map(static fn ($value) => match (true) { + is_object($value) => 'Object(' . $value::class . ')', + is_array($value) => $value !== [] ? '[...]' : '[]', + $value === null => 'null', // return the lowercased version + default => var_export($value, true), + }, array_values($error['args'] ?? []))); $function .= '(' . $args . ')'; diff --git a/app/Views/errors/cli/production.php b/app/Views/errors/cli/production.php index 7db744ec..f1dacf1b 100644 --- a/app/Views/errors/cli/production.php +++ b/app/Views/errors/cli/production.php @@ -1,5 +1,7 @@ + + + + <?= lang('Errors.badRequest') ?> + + + + +
+

400

+ +

+ + + + + +

+
+ + diff --git a/app/Views/errors/html/error_403.php b/app/Views/errors/html/error_403.php new file mode 100644 index 00000000..a5d4d040 --- /dev/null +++ b/app/Views/errors/html/error_403.php @@ -0,0 +1,30 @@ + + + + + + + + + 403 Forbidden + ' /> + asset('styles/index.css', 'css') ?> + + + + +

403 - Forbidden

+ +

+ + + + You do not have sufficient permissions to access that page. + +

+ + + + diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php index fd5a8411..4d74a150 100644 --- a/app/Views/errors/html/error_404.php +++ b/app/Views/errors/html/error_404.php @@ -1,29 +1,30 @@ - + - 404 Page Not Found + + + <?= lang('Errors.pageNotFound') ?> + ' /> asset('styles/index.css', 'css') ?> - + -

404 - File Not Found

+

404

-

+

- Sorry! Cannot seem to find the page you were looking for. +

- - 'primary', - 'iconLeft' => 'arrow-left', - ]) ?> + diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 845953b1..1931636f 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -1,50 +1,82 @@ +use CodeIgniter\CodeIgniter; +use CodeIgniter\HTTP\Header; + +$errorId = uniqid('error', true); +?> - <?= esc($title) ?> - - -
+
+ Displayed at — + PHP: — + CodeIgniter: -- + Environment: +
-

at line

+

at line

- +
+
+ getPrevious()) { + $last = $prevException; + ?> + +
+    Caused by:
+    getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+    getMessage())) ?>
+    getMessage())) ?>"
+       rel="noreferrer" target="_blank">search →
+    getFile()) . ':' . $prevException->getLine()) ?>
+    
+ + +
+ +
    @@ -62,79 +94,79 @@ $errorId = uniqid('error', true); ?>
      - $row): ?> + $row) : ?> -
    1. -

      - - - - - {PHP internal code} +

    2. +

      + + + + + {PHP internal code} + + + + +   —   + + + ( arguments ) +

      + + + getParameters(); + } + + foreach ($row['args'] as $key => $value) : ?> + + + + + + +
      name : "#{$key}") ?>
      +
      + + () + - - -   —   - - - ( arguments ) -
      - + +   —   () + +

      - getParameters(); - } - foreach ($row['args'] as $key => $value): ?> - - - - - - -
      name : "#{$key}") ?> -
      -
      + + +
      +
      - - () - +
    3. - -   —   () - -

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

    $

    @@ -146,26 +178,26 @@ $errorId = uniqid('error', true); ?> - $value): ?> - - - - - - -
    - - - - + $value) : ?> + + + + + + +
    + + + + - + - +

    Constants

    @@ -176,18 +208,18 @@ $errorId = uniqid('error', true); ?> - $value): ?> - - - - - + $value) : ?> + + + + +
    - - - -
    - -
    + + + +
    + +
    @@ -195,17 +227,17 @@ $errorId = uniqid('error', true); ?>
    - + - + - + @@ -233,10 +265,11 @@ $errorId = uniqid('error', true); ?> - - + + @@ -250,24 +283,24 @@ $errorId = uniqid('error', true); ?> - $value): ?> - - - - - + $value) : ?> + + + + +
    Pathuri) ?>getUri()) ?>
    HTTP MethodgetMethod(true)) ?>getMethod()) ?>
    IP Address
    - - - -
    - -
    + + + +
    + +
    - + - +
    No $_GET, $_POST, or $_COOKIE Information to show. @@ -275,8 +308,8 @@ $errorId = uniqid('error', true); ?> - getHeaders(); ?> - + headers(); ?> +

    Headers

    @@ -288,20 +321,22 @@ $errorId = uniqid('error', true); ?> - - - - - - getName(), 'html') ?> - getValueLine(), 'html') ?> - - - + $value) : ?> + + + + getValueLine(), 'html'); + } else { + foreach ($value as $i => $header) { + echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html'); + } + } + ?> + + + @@ -310,21 +345,19 @@ $errorId = uniqid('error', true); ?> setStatusCode(http_response_code()); - ?> + $response = service('response'); +$response->setStatusCode(http_response_code()); +?>
    - +
    Response StatusgetStatusCode() . ' - ' . $response->getReason()) ?>getStatusCode() . ' - ' . $response->getReasonPhrase()) ?>
    - getHeaders(); ?> - - - + headers(); ?> +

    Headers

    @@ -335,12 +368,22 @@ $errorId = uniqid('error', true); ?> - - - - - - + $value) : ?> + + + + +
    getHeaderLine($name), 'html') ?>
    + getHeaderLine($name), 'html'); + } else { + foreach ($value as $i => $header) { + echo ' (' . $i + 1 . ') ' . esc($header->getValueLine(), 'html'); + } + } + ?> +
    @@ -352,9 +395,9 @@ $errorId = uniqid('error', true); ?>
      - -
    1. - + +
    2. +
    @@ -383,19 +426,7 @@ $errorId = uniqid('error', true); ?>
    - - + - diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php index 9570a0eb..77445e16 100644 --- a/app/Views/errors/html/production.php +++ b/app/Views/errors/html/production.php @@ -5,15 +5,55 @@ + - Whoops! + <?= lang('Errors.whoops') ?> + ' /> asset('styles/index.css', 'css') ?> + loggedIn()): ?> + asset('js/error.ts', 'js') ?> + - - -

    Whoops!

    -

    We seem to have hit a snag. Please try again later...

    + + loggedIn()): ?> +
    +
    + +

    +

    +
    +
    +

    getCode() ? ' #' . $exception->getCode() : '') ?>

    +

    getMessage())) ?>
    at getFile())) ?>:getLine()) ?>

    + + + 'mr-2', + ]) ?>Copy stack trace + + +
    +
    +
    +
    +

    Found a bug?

    +

    You can help get it fixed by creating an issue on the Castopod issue tracker. Please check that the issue does not already exist beforehand.

    +
    +
    +

    Not sure what's happening?

    +

    You can ask for help in the Castopod community chat!

    +
    +
    + +
    + +

    Whoops!

    +

    We seem to have hit a snag. Please try again later...

    +
    + - diff --git a/app/Views/home.php b/app/Views/home.php deleted file mode 100644 index 9c937149..00000000 --- a/app/Views/home.php +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - Castopod - - - - asset('styles/index.css', 'css') ?> - - - -
    -
    - -
    -
    -
    -

    ()

    -
    - - - -
    - <?= $podcast->title ?> -

    title ?>

    -

    @name ?>

    -
    -
    - - -

    - -
    -
    - - diff --git a/app/Views/install/_layout.php b/app/Views/install/_layout.php deleted file mode 100644 index 91920f08..00000000 --- a/app/Views/install/_layout.php +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Castopod - - - - asset('styles/index.css', 'css') ?> - asset('js/install.ts', 'js') ?> - - - -
    -
    - Castopod installer -
    -
    -
    - - renderSection('content') ?> -
    - - diff --git a/app/Views/install/cache_config.php b/app/Views/install/cache_config.php deleted file mode 100644 index 3a254303..00000000 --- a/app/Views/install/cache_config.php +++ /dev/null @@ -1,44 +0,0 @@ -extend('install/_layout') ?> - -section('content') ?> - - 'flex flex-col max-w-sm w-full', -]) ?> - - -

    3/4

    - -

    - - - lang('Install.form.cacheHandlerOptions.file'), - 'redis' => lang('Install.form.cacheHandlerOptions.redis'), - 'predis' => lang('Install.form.cacheHandlerOptions.predis'), - ], - old('cache_handler', 'file'), - [ - 'id' => 'cache_handler', - 'name' => 'cache_handler', - 'class' => 'form-select mb-6', - 'value' => config('Database')->default['DBPrefix'], - ], -) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/install/create_superadmin.php b/app/Views/install/create_superadmin.php deleted file mode 100644 index 4363cfd9..00000000 --- a/app/Views/install/create_superadmin.php +++ /dev/null @@ -1,52 +0,0 @@ -extend('install/_layout') ?> - -section('content') ?> - - 'flex flex-col max-w-sm w-full', -]) ?> - - -

    4/4

    - - - 'email', - 'name' => 'email', - 'class' => 'form-input mb-4', - 'type' => 'email', - 'required' => 'required', - 'value' => old('email'), -]) ?> - - - 'username', - 'name' => 'username', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'value' => old('username'), -]) ?> - - - 'password', - 'name' => 'password', - 'class' => 'form-input mb-4', - 'type' => 'password', - 'required' => 'required', - 'autocomplete' => 'new-password', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/install/database_config.php b/app/Views/install/database_config.php deleted file mode 100644 index 5a887dd6..00000000 --- a/app/Views/install/database_config.php +++ /dev/null @@ -1,80 +0,0 @@ -extend('install/_layout') ?> - -section('content') ?> - - 'flex flex-col max-w-sm w-full', - 'autocomplete' => 'off', -]) ?> - - -

    2/4

    - -

    - - - 'db_hostname', - 'name' => 'db_hostname', - 'class' => 'form-input mb-4', - 'value' => old('db_hostname', config('Database')->default['hostname']), - 'required' => 'required', -]) ?> - - - 'db_name', - 'name' => 'db_name', - 'class' => 'form-input mb-4', - 'value' => old('db_name', config('Database')->default['database']), - 'required' => 'required', -]) ?> - - - 'db_username', - 'name' => 'db_username', - 'class' => 'form-input mb-4', - 'value' => old('db_username', config('Database')->default['username']), - 'required' => 'required', - 'autocomplete' => 'off', -]) ?> - - - 'db_password', - 'name' => 'db_password', - 'class' => 'form-input mb-4', - 'value' => old('db_password', config('Database')->default['password']), - 'type' => 'password', - 'required' => 'required', - 'autocomplete' => 'off', -]) ?> - - - 'db_prefix', - 'name' => 'db_prefix', - 'class' => 'form-input mb-6', - 'value' => old('db_prefix', config('Database')->default['DBPrefix']), -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/install/instance_config.php b/app/Views/install/instance_config.php deleted file mode 100644 index 18e3e63e..00000000 --- a/app/Views/install/instance_config.php +++ /dev/null @@ -1,77 +0,0 @@ -extend('install/_layout') ?> - -section('content') ?> - -
    - - -

    1/4

    - - 'hostname', - 'name' => 'hostname', - 'class' => 'form-input mb-4', - 'value' => old( - 'hostname', - host_url() === null ? config('App')->baseURL : host_url(), - ), - 'required' => 'required', -]) ?> - - - - 'media_base_url', - 'name' => 'media_base_url', - 'class' => 'form-input mb-4', - 'value' => old('media_base_url', ''), -]) ?> - - - 'admin_gateway', - 'name' => 'admin_gateway', - 'class' => 'form-input mb-4', - 'value' => old('admin_gateway', config('App')->adminGateway), - 'required' => 'required', -]) ?> - - - 'auth_gateway', - 'name' => 'auth_gateway', - 'class' => 'form-input mb-6', - 'value' => old('auth_gateway', config('App')->authGateway), - 'required' => 'required', -]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], -) ?> - - - -endSection() ?> diff --git a/app/Views/install/manual_config.php b/app/Views/install/manual_config.php deleted file mode 100644 index 26fb5ed1..00000000 --- a/app/Views/install/manual_config.php +++ /dev/null @@ -1,16 +0,0 @@ -extend('install/_layout') ?> - -section('content') ?> - -

    -
    - -
    -

    - -endSection() -?> diff --git a/app/Views/map.php b/app/Views/map.php deleted file mode 100644 index 4daeb9f7..00000000 --- a/app/Views/map.php +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - <?= lang('Page.map') ?> - - - - asset('styles/index.css', 'css') ?> - asset('js/map.ts', 'js') ?> - - - -
    -
    - -

    -
    -
    -
    -
    -
    - - diff --git a/app/Views/page.php b/app/Views/page.php deleted file mode 100644 index e71877f0..00000000 --- a/app/Views/page.php +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - <?= $page->title ?> - - - asset('styles/index.css', 'css') ?> - - - -
    -
    - -

    title ?>

    -
    -
    -
    -
    - content_html ?> -
    -
    - - diff --git a/app/Views/pager/default_full.php b/app/Views/pager/default_full.php index 2f002792..e82fefa8 100644 --- a/app/Views/pager/default_full.php +++ b/app/Views/pager/default_full.php @@ -1,10 +1,8 @@ -setSurroundCount(2); ?> @@ -13,15 +11,15 @@ $pager->setSurroundCount(2); hasPreviousPage()): ?>
  • + 'Pager.first', + ) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
  • + 'Pager.previous', + ) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight"> @@ -32,13 +30,11 @@ $pager->setSurroundCount(2); links() as $link): ?>
  • - + - + @@ -48,15 +44,15 @@ $pager->setSurroundCount(2); hasNextPage()): ?>
  • + 'Pager.next', + ) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
  • + 'Pager.last', + ) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
  • diff --git a/app/Views/podcast/_layout.php b/app/Views/podcast/_layout.php deleted file mode 100644 index 4b850f35..00000000 --- a/app/Views/podcast/_layout.php +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - renderSection('meta-tags') ?> - payment_pointer): ?> - - - - asset('styles/index.css', 'css') ?> - asset('js/podcast.ts', 'js') ?> - - - - include('podcast/_partials/header') ?> - -
    - renderSection('content') ?> -
    - - include('podcast/_partials/sidebar') ?> - - - - - - - diff --git a/app/Views/podcast/_layout_authenticated.php b/app/Views/podcast/_layout_authenticated.php deleted file mode 100644 index 74c82a62..00000000 --- a/app/Views/podcast/_layout_authenticated.php +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - renderSection('meta-tags') ?> - payment_pointer): ?> - - - - asset('styles/index.css', 'css') ?> - asset('js/podcast.ts', 'js') ?> - - - -
    - - 'text-2xl inline-flex items-baseline font-bold font-display', - ], - ) ?> - podcasts !== []): ?> - - - -
    - include('podcast/_partials/header') ?> - -
    - renderSection('content') ?> -
    - - include('podcast/_partials/sidebar') ?> - - - - - - - - diff --git a/app/Views/podcast/_partials/episode_card.php b/app/Views/podcast/_partials/episode_card.php deleted file mode 100644 index c64e82bd..00000000 --- a/app/Views/podcast/_partials/episode_card.php +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/app/Views/podcast/_partials/header.php b/app/Views/podcast/_partials/header.php deleted file mode 100644 index 1c15b4ad..00000000 --- a/app/Views/podcast/_partials/header.php +++ /dev/null @@ -1,58 +0,0 @@ -
    - -
    - <?= $podcast->title ?> - name), - icon( - 'social/castopod', - 'mr-2 text-xl text-pink-200 group-hover:text-pink-50', - ) . lang('Podcast.follow'), - [ - 'width' => 420, - 'height' => 620, - 'class' => - 'group inline-flex items-center px-4 py-2 text-xs tracking-wider font-semibold text-white uppercase rounded-full shadow focus:outline-none focus:ring bg-rose-600', - ], - ) ?> -
    -
    -

    title . - ($podcast->parental_advisory === 'explicit' - ? '' . - lang('Common.explicit') . - '' - : '') ?>

    -

    @name ?>

    -
    description_html ?>
    - location, 'text-sm mb-4') ?> -
    - - category->code, - ) ?> - - other_categories as $other_category): ?> - - code, - ) ?> - - -
    - persons, 'mb-6') ?> - -
    -
    diff --git a/app/Views/podcast/_partials/preview_card.php b/app/Views/podcast/_partials/preview_card.php deleted file mode 100644 index cf2b58ba..00000000 --- a/app/Views/podcast/_partials/preview_card.php +++ /dev/null @@ -1,45 +0,0 @@ -type === 'image'): ?> - - image): ?> -
    - - <?= $preview_card->title ?> -
    - - -
    - provider_name ?> -
    -
    -type === 'video'): ?> - - image): ?> -
    - - <?= $preview_card->title ?> -
    - - -
    - provider_name ?> - title ?> -
    -
    - - - image): ?> - <?= $preview_card->title ?> - -

    - provider_name ?> - title ?> -

    -
    - diff --git a/app/Views/podcast/_partials/reblog.php b/app/Views/podcast/_partials/reblog.php deleted file mode 100644 index 8b192bb9..00000000 --- a/app/Views/podcast/_partials/reblog.php +++ /dev/null @@ -1,47 +0,0 @@ - diff --git a/app/Views/podcast/_partials/reblog_authenticated.php b/app/Views/podcast/_partials/reblog_authenticated.php deleted file mode 100644 index d3bd79eb..00000000 --- a/app/Views/podcast/_partials/reblog_authenticated.php +++ /dev/null @@ -1,47 +0,0 @@ - diff --git a/app/Views/podcast/_partials/reply.php b/app/Views/podcast/_partials/reply.php deleted file mode 100644 index 8fb48bf8..00000000 --- a/app/Views/podcast/_partials/reply.php +++ /dev/null @@ -1,29 +0,0 @@ - diff --git a/app/Views/podcast/_partials/reply_actions.php b/app/Views/podcast/_partials/reply_actions.php deleted file mode 100644 index 7e694143..00000000 --- a/app/Views/podcast/_partials/reply_actions.php +++ /dev/null @@ -1,36 +0,0 @@ -
    - name, $reply->id), - icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'title' => lang('Status.replies', [ - 'numberOfReplies' => $reply->replies_count, - ]), - ], - ) ?> - name, $reply->id, 'reblog'), - icon('repeat', 'text-xl mr-1 text-gray-400') . $reply->reblogs_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'width' => 420, - 'height' => 620, - 'title' => lang('Status.reblogs', [ - 'numberOfReblogs' => $reply->reblogs_count, - ]), - ], - ) ?> - name, $reply->id, 'favourite'), - icon('heart', 'text-xl mr-1 text-gray-400') . $reply->favourites_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'width' => 420, - 'height' => 620, - 'title' => lang('Status.favourites', [ - 'numberOfFavourites' => $reply->favourites_count, - ]), - ], - ) ?> -
    diff --git a/app/Views/podcast/_partials/reply_actions_authenticated.php b/app/Views/podcast/_partials/reply_actions_authenticated.php deleted file mode 100644 index faa7a310..00000000 --- a/app/Views/podcast/_partials/reply_actions_authenticated.php +++ /dev/null @@ -1,89 +0,0 @@ -
    -
    - - name, $reply->id), - icon('chat', 'text-xl mr-1 text-gray-400') . $reply->replies_count, - [ - 'class' => 'inline-flex items-center mr-6 hover:underline', - 'title' => lang('Status.replies', [ - 'numberOfReplies' => $reply->replies_count, - ]), - ], - ) ?> - - - -
    - -
    diff --git a/app/Views/podcast/_partials/reply_authenticated.php b/app/Views/podcast/_partials/reply_authenticated.php deleted file mode 100644 index ab264ce5..00000000 --- a/app/Views/podcast/_partials/reply_authenticated.php +++ /dev/null @@ -1,29 +0,0 @@ - diff --git a/app/Views/podcast/_partials/sidebar.php b/app/Views/podcast/_partials/sidebar.php deleted file mode 100644 index 6d703437..00000000 --- a/app/Views/podcast/_partials/sidebar.php +++ /dev/null @@ -1,85 +0,0 @@ - diff --git a/app/Views/podcast/_partials/status.php b/app/Views/podcast/_partials/status.php deleted file mode 100644 index b707d127..00000000 --- a/app/Views/podcast/_partials/status.php +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/app/Views/podcast/_partials/status_actions.php b/app/Views/podcast/_partials/status_actions.php deleted file mode 100644 index 625c684a..00000000 --- a/app/Views/podcast/_partials/status_actions.php +++ /dev/null @@ -1,36 +0,0 @@ -
    - name, $status->id), - icon('chat', 'text-2xl mr-1 text-gray-400') . $status->replies_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'title' => lang('Status.replies', [ - 'numberOfReplies' => $status->replies_count, - ]), - ], - ) ?> - name, $status->id, 'reblog'), - icon('repeat', 'text-2xl mr-1 text-gray-400') . $status->reblogs_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'width' => 420, - 'height' => 620, - 'title' => lang('Status.reblogs', [ - 'numberOfReblogs' => $status->reblogs_count, - ]), - ], - ) ?> - name, $status->id, 'favourite'), - icon('heart', 'text-2xl mr-1 text-gray-400') . $status->favourites_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'width' => 420, - 'height' => 620, - 'title' => lang('Status.favourites', [ - 'numberOfFavourites' => $status->favourites_count, - ]), - ], - ) ?> -
    diff --git a/app/Views/podcast/_partials/status_actions_authenticated.php b/app/Views/podcast/_partials/status_actions_authenticated.php deleted file mode 100644 index 8d4aab14..00000000 --- a/app/Views/podcast/_partials/status_actions_authenticated.php +++ /dev/null @@ -1,89 +0,0 @@ -
    -
    - - name, $status->id), - icon('chat', 'text-2xl mr-1 text-gray-400') . $status->replies_count, - [ - 'class' => 'inline-flex items-center hover:underline', - 'title' => lang('Status.replies', [ - 'numberOfReplies' => $status->replies_count, - ]), - ], - ) ?> - - - -
    - -
    diff --git a/app/Views/podcast/_partials/status_authenticated.php b/app/Views/podcast/_partials/status_authenticated.php deleted file mode 100644 index a4453239..00000000 --- a/app/Views/podcast/_partials/status_authenticated.php +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/app/Views/podcast/_partials/status_with_replies.php b/app/Views/podcast/_partials/status_with_replies.php deleted file mode 100644 index 11f2a7b6..00000000 --- a/app/Views/podcast/_partials/status_with_replies.php +++ /dev/null @@ -1,23 +0,0 @@ -include('podcast/_partials/status') ?> -
    - -
    -name, $status->id, 'reply'), - lang('Status.reply_to', ['actorUsername' => $status->actor->username]), - [ - 'class' => - 'text-center justify-center font-semibold rounded-full shadow relative z-10 px-4 py-2 w-full bg-rose-600 text-white inline-flex items-center hover:bg-rose-700', - 'width' => 420, - 'height' => 620, - ], -) ?> -
    - - -has_replies): ?> - replies as $reply): ?> - $reply]) ?> - - -
    diff --git a/app/Views/podcast/_partials/status_with_replies_authenticated.php b/app/Views/podcast/_partials/status_with_replies_authenticated.php deleted file mode 100644 index eb6d3308..00000000 --- a/app/Views/podcast/_partials/status_with_replies_authenticated.php +++ /dev/null @@ -1,49 +0,0 @@ -include('podcast/_partials/status_authenticated') ?> -
    -username, $status->id), - [ - 'class' => 'bg-gray-50 flex px-6 pt-8 pb-4', - ], -) ?> -<?= interact_as_actor()
-    ->display_name ?> -
    - 'message', - 'name' => 'message', - 'class' => 'form-textarea mb-4 w-full', - 'required' => 'required', - 'placeholder' => lang('Status.form.reply_to_placeholder', [ - 'actorUsername' => $status->actor->username, - ]), - ], - old('message', '', false), - [ - 'rows' => 1, - ], -) ?> - 'primary', 'size' => 'small'], - [ - 'type' => 'submit', - 'class' => 'self-end', - 'name' => 'action', - 'value' => 'reply', - ], -) ?> -
    - - -has_replies): ?> - replies as $reply): ?> - $reply, - ]) ?> - - -
    diff --git a/app/Views/podcast/activity.php b/app/Views/podcast/activity.php deleted file mode 100644 index 1873855f..00000000 --- a/app/Views/podcast/activity.php +++ /dev/null @@ -1,52 +0,0 @@ -extend('podcast/_layout') ?> - -section('meta-tags') ?> - - -<?= $podcast->title ?> - - - - - - - - - - - - -endSection() ?> - -section('content') ?> - - - -
    - - reblog_of_id !== null): ?> - $status->reblog_of_status, - ]) ?> - - $status]) ?> - - -
    - -endSection() ?> diff --git a/app/Views/podcast/activity_authenticated.php b/app/Views/podcast/activity_authenticated.php deleted file mode 100644 index 97151e2e..00000000 --- a/app/Views/podcast/activity_authenticated.php +++ /dev/null @@ -1,98 +0,0 @@ -extend('podcast/_layout_authenticated') ?> - -section('meta-tags') ?> - - -<?= $podcast->title ?> - - - - - - - - - - - - -endSection() ?> - -section('content') ?> - - - -
    -username), [ - 'class' => 'flex p-4 bg-white shadow rounded-xl', -]) ?> - - - - - <?= interact_as_actor()
-    ->display_name ?> -
    - 'message', - 'name' => 'message', - 'class' => 'form-textarea', - 'required' => 'required', - 'placeholder' => lang('Status.form.message_placeholder'), - ], - old('message', '', false), - ['rows' => 2], - ) ?> - 'episode_url', - 'name' => 'episode_url', - 'class' => 'form-input mb-2', - 'placeholder' => - lang('Status.form.episode_url_placeholder') . - ' (' . - lang('Common.optional') . - ')', - 'type' => 'url', - ]) ?> - - 'primary', 'size' => 'small'], - ['type' => 'submit', 'class' => 'self-end'], - ) ?> -
    - -
    - -
    - - reblog_of_id !== null): ?> - $status->reblog_of_status, - ]) ?> - - $status]) ?> - - -
    -
    - -endSection() ?> diff --git a/app/Views/podcast/episode.php b/app/Views/podcast/episode.php deleted file mode 100644 index 245a79d7..00000000 --- a/app/Views/podcast/episode.php +++ /dev/null @@ -1,154 +0,0 @@ -extend('podcast/_layout') ?> - -section('meta-tags') ?> -<?= $episode->title ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -endSection() ?> - -section('content') ?> -
    - $podcast->title]) ?> -
    -
    - <?= $episode->title ?> -
    -

    title ?>

    - number, - $episode->season_number, - 'text-gray-700', - ) ?> -
    - - - -
    -
    - name, $episode->slug), - icon('chat', 'text-xl mr-1 text-gray-400') . - $episode->statuses_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_statuses', [ - 'numberOfTotalStatuses' => $episode->statuses_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('repeat', 'text-xl mr-1 text-gray-400') . - $episode->reblogs_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_reblogs', [ - 'numberOfTotalReblogs' => - $episode->reblogs_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('heart', 'text-xl mr-1 text-gray-400') . - $episode->favourites_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_favourites', [ - 'numberOfTotalFavourites' => - $episode->favourites_total, - ]), - ], - ) ?> -
    - location, 'text-sm mb-4') ?> - persons) ?> -
    -
    - -
    - -
    - statuses): ?> - - - - - - statuses - ? '' - : 'checked="checked"' ?> /> - - -
    - statuses): ?> -
    - statuses as $status): ?> - $status]) ?> - -
    - -
    - getDescriptionHtml('-+Website+-') ?> -
    -
    -
    -
    - -endSection() -?> diff --git a/app/Views/podcast/episode_authenticated.php b/app/Views/podcast/episode_authenticated.php deleted file mode 100644 index 6d419831..00000000 --- a/app/Views/podcast/episode_authenticated.php +++ /dev/null @@ -1,188 +0,0 @@ -extend('podcast/_layout_authenticated') ?> - -section('meta-tags') ?> -<?= $episode->title ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -endSection() ?> - -section('content') ?> -
    - $podcast->title]) ?> -
    -
    - <?= $episode->title ?> -
    -

    title ?>

    - number, - $episode->season_number, - 'text-gray-700', - ) ?> -
    - - - -
    -
    - name, $episode->slug), - icon('chat', 'text-xl mr-1 text-gray-400') . - $episode->statuses_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_statuses', [ - 'numberOfTotalStatuses' => $episode->statuses_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('repeat', 'text-xl mr-1 text-gray-400') . - $episode->reblogs_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_reblogs', [ - 'numberOfTotalReblogs' => - $episode->reblogs_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('heart', 'text-xl mr-1 text-gray-400') . - $episode->favourites_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_favourites', [ - 'numberOfTotalFavourites' => - $episode->favourites_total, - ]), - ], - ) ?> -
    - location, 'text-sm mb-4') ?> - persons) ?> -
    -
    - -
    - -
    - - - - - - -
    -
    - name), [ - 'class' => 'flex p-4 bg-white shadow rounded-xl', - ]) ?> - - - - - <?= interact_as_actor()
-    ->display_name ?> -
    - 'message', - 'name' => 'message', - 'class' => 'form-textarea mb-2', - 'required' => 'required', - 'placeholder' => lang( - 'Status.form.episode_message_placeholder', - ), - ], - old('message', '', false), - [ - 'rows' => 2, - ], - ) ?> - 'episode_url', - 'name' => 'episode_url', - 'value' => $episode->link, - 'type' => 'hidden', - ]) ?> - 'primary', 'size' => 'small'], - ['type' => 'submit', 'class' => 'self-end'], - ) ?> -
    - -
    - statuses as $status): ?> - $status, - ]) ?> - -
    -
    - getDescriptionHtml('-+Website+-') ?> -
    -
    -
    -
    - -endSection() -?> diff --git a/app/Views/podcast/episodes.php b/app/Views/podcast/episodes.php deleted file mode 100644 index 35e5cb5c..00000000 --- a/app/Views/podcast/episodes.php +++ /dev/null @@ -1,171 +0,0 @@ -extend('podcast/_layout') ?> - -section('meta-tags') ?> - - -<?= $podcast->title ?> - - - - - - - - - - - - -endSection() ?> - -section('content') ?> - - -
    - - -

    - - $activeQuery['value'], - 'episodeCount' => count($episodes), - ]) ?> - - $activeQuery['value'], - 'episodeCount' => count($episodes), - ]) ?> - -

    - -
    -
    - <?= $episode->title ?> -
    - -

    - title ?> - number, - $episode->season_number, - 'text-xs font-semibold text-gray-600', - true, - ) ?> -

    -
    -
    - - - -
    - -
    -
    -
    - name, $episode->slug), - icon('chat', 'text-xl mr-1 text-gray-400') . - $episode->statuses_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_statuses', [ - 'numberOfTotalStatuses' => $episode->statuses_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('repeat', 'text-xl mr-1 text-gray-400') . - $episode->reblogs_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_reblogs', [ - 'numberOfTotalReblogs' => - $episode->reblogs_total, - ]), - ], - ) ?> - - name, $episode->slug), - icon('heart', 'text-xl mr-1 text-gray-400') . - $episode->favourites_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_favourites', [ - 'numberOfTotalFavourites' => - $episode->favourites_total, - ]), - ], - ) ?> -
    -
    - - -

    -

    - -
    - -endSection() -?> diff --git a/app/Views/podcast/episodes_authenticated.php b/app/Views/podcast/episodes_authenticated.php deleted file mode 100644 index 9fd0e11a..00000000 --- a/app/Views/podcast/episodes_authenticated.php +++ /dev/null @@ -1,170 +0,0 @@ -extend('podcast/_layout_authenticated') ?> - -section('meta-tags') ?> - - -<?= $podcast->title ?> - - - - - - - - - - - - -endSection() ?> - -section('content') ?> - - -
    - - -

    - - $activeQuery['value'], - 'episodeCount' => count($episodes), - ]) ?> - - $activeQuery['value'], - 'episodeCount' => count($episodes), - ]) ?> - -

    - -
    -
    - <?= $episode->title ?> -
    - -

    - title ?> - number, - $episode->season_number, - 'text-xs font-semibold text-gray-600', - true, - ) ?> -

    -
    -
    - - - -
    - -
    -
    -
    - name, $episode->slug), - icon('chat', 'text-xl mr-1 text-gray-400') . - $episode->statuses_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_statuses', [ - 'numberOfTotalStatuses' => $episode->statuses_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('repeat', 'text-xl mr-1 text-gray-400') . - $episode->reblogs_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_reblogs', [ - 'numberOfTotalReblogs' => - $episode->reblogs_total, - ]), - ], - ) ?> - name, $episode->slug), - icon('heart', 'text-xl mr-1 text-gray-400') . - $episode->favourites_total, - [ - 'class' => - 'inline-flex items-center hover:underline', - 'title' => lang('Episode.total_favourites', [ - 'numberOfTotalFavourites' => - $episode->favourites_total, - ]), - ], - ) ?> -
    -
    - - -

    -

    - -
    - -endSection() -?> diff --git a/app/Views/podcast/follow.php b/app/Views/podcast/follow.php deleted file mode 100644 index 227ddc8c..00000000 --- a/app/Views/podcast/follow.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - asset('styles/index.css', 'css') ?> - - <?= lang('Podcast.follow.title', [ - 'actorDisplayName' => $actor->display_name, - ]) ?> - - - - - - - - - - -
    -

    -
    - -
    - <?= $actor->display_name ?> -
    -

    display_name ?>

    -

    @username ?>

    -
    -
    -
    -
    - -
    - username), [ - 'method' => 'post', - 'class' => 'flex flex-col', - ]) ?> - - - - - 'handle', - 'name' => 'handle', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'text', - ]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], - ) ?> - -
    - - - diff --git a/app/Views/podcast/status.php b/app/Views/podcast/status.php deleted file mode 100644 index 21dd8657..00000000 --- a/app/Views/podcast/status.php +++ /dev/null @@ -1,38 +0,0 @@ -extend('podcast/_layout') ?> - -section('meta-tags') ?> - <?= lang('Status.title', [ - 'actorDisplayName' => $status->actor->display_name, - ]) ?> - - - - - - - -endSection() ?> - -section('content') ?> -
    - -
    - include('podcast/_partials/status_with_replies') ?> -
    -
    - -endSection() -?> diff --git a/app/Views/podcast/status_authenticated.php b/app/Views/podcast/status_authenticated.php deleted file mode 100644 index 9b97dc9f..00000000 --- a/app/Views/podcast/status_authenticated.php +++ /dev/null @@ -1,40 +0,0 @@ -extend('podcast/_layout_authenticated') ?> - -section('meta-tags') ?> - <?= lang('Status.title', [ - 'actorDisplayName' => $status->actor->display_name, - ]) ?> - - - - - - - -endSection() ?> - -section('content') ?> -
    - -
    - include( - 'podcast/_partials/status_with_replies_authenticated', - ) ?> -
    -
    - -endSection() -?> diff --git a/app/Views/podcast/status_remote_action.php b/app/Views/podcast/status_remote_action.php deleted file mode 100644 index 5b3e5cd8..00000000 --- a/app/Views/podcast/status_remote_action.php +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - <?= lang('ActivityPub.' . $action . '.title', [ - 'actorDisplayName' => $status->actor->display_name, - ]) ?> - - - - - - - - - asset('styles/index.css', 'css') ?> - asset('js/podcast.ts', 'js') ?> - - - -
    -

    -
    -
    - include('podcast/_partials/status') ?> - - id, $action), - ['method' => 'post', 'class' => 'flex flex-col mt-8'], - ) ?> - - - - - 'handle', - 'name' => 'handle', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'text', - ]) ?> - - 'primary'], - ['type' => 'submit', 'class' => 'self-end'], - ) ?> - -
    - diff --git a/app/index.html b/app/index.html index 5caba05a..242d70c1 100644 --- a/app/index.html +++ b/app/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/builds b/builds index 08b02e16..e7884e0b 100644 --- a/builds +++ b/builds @@ -1,5 +1,8 @@ #!/usr/bin/env php 'vcs', - 'url' => GITHUB_URL, + 'url' => GITHUB_URL, ]; } - // Define the "require" $array['require']['codeigniter4/codeigniter4'] = 'dev-develop'; unset($array['require']['codeigniter4/framework']); - } - - // Release - else { - // Clear 'minimum-stability' + } else { unset($array['minimum-stability']); - // If the repo is configured then clear it if (isset($array['repositories'])) { - // Check for the CodeIgniter repo foreach ($array['repositories'] as $i => $repository) { - if ($repository['url'] == GITHUB_URL) { + if ($repository['url'] === GITHUB_URL) { unset($array['repositories'][$i]); break; } } + if (empty($array['repositories'])) { unset($array['repositories']); } } - // Define the "require" $array['require']['codeigniter4/framework'] = LATEST_RELEASE; unset($array['require']['codeigniter4/codeigniter4']); } - // Write out a new composer.json - file_put_contents( - $file, - json_encode( - $array, - JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES - ) . PHP_EOL - ); + file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL); + $modified[] = $file; } else { - echo 'Warning: Unable to decode composer.json! Skipping...' . - PHP_EOL; + echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL; } } else { echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL; } } -// Paths config and PHPUnit XMLs $files = [ __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php', __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist', @@ -117,37 +102,26 @@ foreach ($files as $file) { if (is_file($file)) { $contents = file_get_contents($file); - // Development if ($dev) { - $contents = str_replace( - 'vendor/codeigniter4/framework', - 'vendor/codeigniter4/codeigniter4', - $contents - ); - } - - // Release - else { - $contents = str_replace( - 'vendor/codeigniter4/codeigniter4', - 'vendor/codeigniter4/framework', - $contents - ); + $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents); + } else { + $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents); } file_put_contents($file, $contents); + $modified[] = $file; } } -if (empty($modified)) { - echo 'No files modified' . PHP_EOL; +if ($modified === []) { + echo 'No files modified.' . PHP_EOL; } else { echo 'The following files were modified:' . PHP_EOL; + foreach ($modified as $file) { echo " * {$file}" . PHP_EOL; } - echo 'Run `composer update` to sync changes with your vendor folder' . - PHP_EOL; -} + echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL; +} diff --git a/captainhook.json b/captainhook.json index 0f0dbb9a..f874e4ef 100644 --- a/captainhook.json +++ b/captainhook.json @@ -18,12 +18,12 @@ "enabled": true, "actions": [ { - "action": "composer test -- --no-coverage", + "action": "composer test", "options": [], "conditions": [] }, { - "action": "composer analyse", + "action": "composer phpstan", "options": [], "conditions": [] }, diff --git a/commitlint.config.cjs b/commitlint.config.cjs new file mode 100644 index 00000000..5073c20d --- /dev/null +++ b/commitlint.config.cjs @@ -0,0 +1 @@ +module.exports = { extends: ["@commitlint/config-conventional"] }; diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 723fa61f..00000000 --- a/commitlint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable */ - -module.exports = { extends: ["@commitlint/config-conventional"] }; diff --git a/composer.json b/composer.json index 48ac0248..f3ce91ba 100644 --- a/composer.json +++ b/composer.json @@ -1,43 +1,52 @@ { - "name": "podlibre/castopod-host", - "version": "1.0.0-alpha80", + "name": "adaures/castopod", + "version": "2.0.0-dev", "type": "project", - "description": "Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.", + "description": "Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.", "homepage": "https://castopod.org", "license": "AGPL-3.0-or-later", "require": { - "php": "^8.0", - "james-heinrich/getid3": "^2.0.x-dev", - "whichbrowser/parser": "^v2.1.1", - "geoip2/geoip2": "^v2.11.0", - "myth/auth": "dev-develop", - "codeigniter4/codeigniter4": "dev-develop", - "league/commonmark": "^1.6.2", - "vlucas/phpdotenv": "^v5.3.0", - "league/html-to-markdown": "^4.10.0", - "opawg/user-agents-php": "^v1.0", - "podlibre/ipcat": "^v1.0", - "podlibre/podcast-namespace": "^v1.0.6", - "phpseclib/phpseclib": "~2.0.30", - "michalsn/codeigniter4-uuid": "dev-develop", - "essence/essence": "^3.5.4" + "php": "^8.5", + "adaures/castopod-plugins-manager": "dev-main", + "adaures/ipcat-php": "^v1.0.0", + "adaures/podcast-persons-taxonomy": "^v1.0.1", + "aws/aws-sdk-php": "^3.369.37", + "chrisjean/php-ico": "^1.0.4", + "cocur/slugify": "4.7.1", + "codeigniter4/framework": "4.7.0", + "codeigniter4/settings": "v2.2.0", + "codeigniter4/shield": "1.2.0", + "codeigniter4/tasks": "dev-develop", + "geoip2/geoip2": "3.3.0", + "james-heinrich/getid3": "^2.0.0-beta6", + "league/commonmark": "^2.8.0", + "league/html-to-markdown": "5.1.1", + "melbahja/seo": "3.0.2", + "michalsn/codeigniter4-uuid": "1.3.1", + "mpratt/embera": "^2.0.42", + "opawg/user-agents-v2-php": "dev-main", + "phpseclib/phpseclib": "~2.0.51", + "vlucas/phpdotenv": "5.6.3", + "whichbrowser/parser": "^v2.1.8", + "yassinedoghri/codeigniter-vite": "^2.1.0", + "yassinedoghri/php-icons": "1.3.0", + "yassinedoghri/podcast-feed": "dev-main" }, "require-dev": { - "mikey179/vfsstream": "^v1.6.8", - "phpunit/phpunit": "^9.5.4", - "rector/rector": "^0.11.5", - "captainhook/captainhook": "^5.10.0", - "phpstan/phpstan": "^0.12.85", - "phpstan/extension-installer": "^1.1.0", - "rector/rector-phpstan-rules": "^0.2.9", - "symplify/phpstan-extensions": "^v9.3.12", - "symplify/easy-coding-standard": "^v9.3.12", - "symplify/coding-standard": "^v9.3.12" + "captainhook/captainhook": "^5.28.3", + "codeigniter/phpstan-codeigniter": "1.5.4", + "mikey179/vfsstream": "^v1.6.12", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.39", + "phpunit/phpunit": "^13.0.5", + "rector/rector": "^2.3.6", + "symplify/coding-standard": "^13.0.0", + "symplify/easy-coding-standard": "^13.0.4" }, "autoload": { "psr-4": { - "App\\": "app", - "Config\\": "app/Config" + "App\\": "app/", + "Config\\": "app/Config/" }, "exclude-from-classmap": [ "**/Database/Migrations/**" @@ -49,40 +58,53 @@ } }, "scripts": { - "test": "vendor/bin/phpunit", - "analyse": "vendor/bin/phpstan analyse --ansi", - "rector": "vendor/bin/rector process --dry-run --ansi", - "rector:fix": "vendor/bin/rector process --ansi", + "dev": "php spark serve", + "test": "vendor/bin/phpunit --no-coverage", + "phpstan": "vendor/bin/phpstan analyse --ansi", + "rector": "vendor/bin/rector process --dry-run --ansi --memory-limit=2G", + "rector:fix": "vendor/bin/rector process --ansi --memory-limit=2G", "style": "vendor/bin/ecs check --ansi", "style:fix": "vendor/bin/ecs check --fix --ansi", + "generate:auth-docs": "php spark auth:generate-docs", + "php-icons": "vendor/bin/php-icons scan", "post-install-cmd": [ - "@php vendor/opawg/user-agents-php/src/UserAgentsGenerate.php > vendor/opawg/user-agents-php/src/UserAgents.php", - "@php vendor/opawg/user-agents-php/src/UserAgentsRSSGenerate.php > vendor/opawg/user-agents-php/src/UserAgentsRSS.php", - "@php vendor/podlibre/ipcat/IpDbGenerate.php > vendor/podlibre/ipcat/IpDb.php", - "@php vendor/podlibre/podcast-namespace/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > app/Language/en/PersonsTaxonomy.php", - "@php vendor/podlibre/podcast-namespace/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-fr.json > app/Language/fr/PersonsTaxonomy.php", - "@php vendor/podlibre/podcast-namespace/src/ReversedTaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > vendor/podlibre/podcast-namespace/src/ReversedTaxonomy.php" + "@php vendor/opawg/user-agents-v2-php/src/UserAgentsGenerate.php > vendor/opawg/user-agents-v2-php/src/UserAgents.php", + "@php vendor/opawg/user-agents-v2-php/src/UserAgentsRSSGenerate.php > vendor/opawg/user-agents-v2-php/src/UserAgentsRSS.php", + "@php vendor/adaures/ipcat-php/src/IpDbGenerate.php > vendor/adaures/ipcat-php/src/IpDb.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > modules/Admin/Language/en/PersonsTaxonomy.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-fr.json > modules/Admin/Language/fr/PersonsTaxonomy.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/ReversedTaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > vendor/adaures/podcast-persons-taxonomy/src/ReversedTaxonomy.php", + "vendor/bin/php-icons init && vendor/bin/php-icons scan" ], "post-update-cmd": [ "@composer dump-autoload", - "@php vendor/opawg/user-agents-php/src/UserAgentsGenerate.php > vendor/opawg/user-agents-php/src/UserAgents.php", - "@php vendor/opawg/user-agents-php/src/UserAgentsRSSGenerate.php > vendor/opawg/user-agents-php/src/UserAgentsRSS.php", - "@php vendor/podlibre/ipcat/IpDbGenerate.php > vendor/podlibre/ipcat/IpDb.php", - "@php vendor/podlibre/podcast-namespace/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > app/Language/en/PersonsTaxonomy.php", - "@php vendor/podlibre/podcast-namespace/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-fr.json > app/Language/fr/PersonsTaxonomy.php", - "@php vendor/podlibre/podcast-namespace/src/ReversedTaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > vendor/podlibre/podcast-namespace/src/ReversedTaxonomy.php" + "@php vendor/opawg/user-agents-v2-php/src/UserAgentsGenerate.php > vendor/opawg/user-agents-v2-php/src/UserAgents.php", + "@php vendor/opawg/user-agents-v2-php/src/UserAgentsRSSGenerate.php > vendor/opawg/user-agents-v2-php/src/UserAgentsRSS.php", + "@php vendor/adaures/ipcat-php/src/IpDbGenerate.php > vendor/adaures/ipcat-php/src/IpDb.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > modules/Admin/Language/en/PersonsTaxonomy.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/TaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-fr.json > modules/Admin/Language/fr/PersonsTaxonomy.php", + "@php vendor/adaures/podcast-persons-taxonomy/src/ReversedTaxonomyGenerate.php https://raw.githubusercontent.com/Podcastindex-org/podcast-namespace/main/taxonomy-en.json > vendor/adaures/podcast-persons-taxonomy/src/ReversedTaxonomy.php", + "vendor/bin/php-icons init && vendor/bin/php-icons scan" ] }, "support": { - "source": "https://code.podlibre.org/podlibre/castopod-host.git", + "source": "https://code.castopod.org/adaures/castopod.git", "discord": "https://castopod.org/discord" }, "minimum-stability": "dev", "prefer-stable": true, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "phpstan/extension-installer": true + } + }, "repositories": [ { "type": "vcs", - "url": "https://github.com/codeigniter4/codeigniter4" + "url": "https://github.com/codeigniter4/tasks.git" } ] } diff --git a/composer.lock b/composer.lock index 0646c92f..3e35a5dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,379 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "af4a438816f7adbbd6950d93ed333e9f", + "content-hash": "de1c665976cbb37fec3de326336d83f5", "packages": [ { - "name": "brick/math", - "version": "0.9.2", + "name": "adaures/castopod-plugins-manager", + "version": "dev-main", "source": { "type": "git", - "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "url": "https://github.com/ad-aures/castopod-plugins-manager.git", + "reference": "53430f9a57cd38eee3e3dfe5953764cc42c2a0c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/ad-aures/castopod-plugins-manager/zipball/53430f9a57cd38eee3e3dfe5953764cc42c2a0c9", + "reference": "53430f9a57cd38eee3e3dfe5953764cc42c2a0c9", "shasum": "" }, "require": { + "php": ">=8.4", + "z4kn4fein/php-semver": "^3.0" + }, + "require-dev": { + "pestphp/pest": "^4.0.4", + "pestphp/pest-plugin-type-coverage": "^4.0.2", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "rector/rector": "^2.1.4", + "symplify/coding-standard": "^12.4.3", + "symplify/easy-coding-standard": "^12.5.24" + }, + "default-branch": true, + "type": "library", + "autoload": { + "files": [ + "src/Constants.php", + "src/helpers.php" + ], + "psr-4": { + "Castopod\\PluginsManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-only" + ], + "authors": [ + { + "name": "Yassine Doghri", + "homepage": "https://yassinedoghri.com/" + } + ], + "description": "A PHP library to install, update, and remove plugins on a Castopod instance.", + "support": { + "issues": "https://github.com/ad-aures/castopod-plugins-manager/issues", + "source": "https://github.com/ad-aures/castopod-plugins-manager/tree/main" + }, + "time": "2025-10-06T15:58:43+00:00" + }, + { + "name": "adaures/ipcat-php", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://code.castopod.org/adaures/ipcat-php", + "reference": "144fb12141c636b6b4baa72f1f974b388e4994b5" + }, + "require": { + "php": ">=5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdAures\\Ipcat\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0-only" + ], + "authors": [ + { + "name": "Benjamin Bellamy", + "email": "ben@castopod.org", + "homepage": "https://code.castopod.org/benjamin" + }, + { + "name": "Yassine Doghri", + "email": "yassine@doghri.fr", + "homepage": "https://code.castopod.org/yassine" + } + ], + "description": "Categorization of IP Addresses adapted to PHP 5.4+ from https://github.com/client9/ipcat", + "homepage": "https://code.castopod.org/adaures/ipcat-php", + "time": "2022-02-24T14:34:54+00:00" + }, + { + "name": "adaures/podcast-persons-taxonomy", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://code.castopod.org/adaures/podcast-persons-taxonomy", + "reference": "d2a6836e32ed013676fd969425e133e0ebb104fc" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdAures\\PodcastPersonsTaxonomy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin Bellamy", + "email": "ben@castopod.org", + "homepage": "https://code.castopod.org/benjamin" + }, + { + "name": "Yassine Doghri", + "email": "yassine@doghri.fr", + "homepage": "https://code.castopod.org/yassine" + } + ], + "description": "Generate PHP translation files for CodeIgniter4 from the podcast-namespace's Persons Taxonomy json files.", + "homepage": "https://code.castopod.org/adaures/podcast-persons-taxonomy", + "time": "2023-06-22T14:24:55+00:00" + }, + { + "name": "adhocore/cli", + "version": "v1.9.4", + "source": { + "type": "git", + "url": "https://github.com/adhocore/php-cli.git", + "reference": "474dc3d7ab139796be98b104d891476e3916b6f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adhocore/php-cli/zipball/474dc3d7ab139796be98b104d891476e3916b6f4", + "reference": "474dc3d7ab139796be98b104d891476e3916b6f4", + "shasum": "" + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ahc\\Cli\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jitendra Adhikari", + "email": "jiten.adhikary@gmail.com" + } + ], + "description": "Command line interface library for PHP", + "keywords": [ + "argument-parser", + "argv-parser", + "cli", + "cli-action", + "cli-app", + "cli-color", + "cli-option", + "cli-writer", + "command", + "console", + "console-app", + "php-cli", + "php8", + "stream-input", + "stream-output" + ], + "support": { + "issues": "https://github.com/adhocore/php-cli/issues", + "source": "https://github.com/adhocore/php-cli/tree/v1.9.4" + }, + "funding": [ + { + "url": "https://paypal.me/ji10", + "type": "custom" + }, + { + "url": "https://github.com/adhocore", + "type": "github" + } + ], + "time": "2025-05-11T13:23:54+00:00" + }, + { + "name": "aws/aws-crt-php", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" + }, + "time": "2024-10-18T22:15:13+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.369.37", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "bc599ce989b101ee630d5e1a1aeda387632df47b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/bc599ce989b101ee630d5e1a1aeda387632df47b", + "reference": "bc599ce989b101ee630d5e1a1aeda387632df47b", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.2.3", "ext-json": "*", - "php": "^7.1 || ^8.0" + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^1.0 || ^2.0", + "symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^9.6", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-pcntl": "To use client-side monitoring", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.369.37" + }, + "time": "2026-02-18T19:16:34+00:00" + }, + { + "name": "brick/math", + "version": "0.14.8", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", + "shasum": "" + }, + "require": { + "php": "^8.2" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "phpstan/phpstan": "2.1.22", + "phpunit/phpunit": "^11.5" }, "type": "library", "autoload": { @@ -36,7 +385,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "description": "Arbitrary-precision arithmetic library", "keywords": [ "Arbitrary-precision", @@ -45,122 +396,549 @@ "arithmetic", "bigdecimal", "bignum", + "bignumber", "brick", - "math" + "decimal", + "integer", + "math", + "mathematics", + "rational" ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" + "url": "https://github.com/BenMorel", + "type": "github" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { - "name": "codeigniter4/codeigniter4", - "version": "dev-develop", + "name": "chrisjean/php-ico", + "version": "1.0.4", "source": { "type": "git", - "url": "https://github.com/codeigniter4/CodeIgniter4.git", - "reference": "995c51f383844bc44a607026ea6ab85b06c7e87e" + "url": "https://github.com/chrisbliss18/php-ico.git", + "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/995c51f383844bc44a607026ea6ab85b06c7e87e", - "reference": "995c51f383844bc44a607026ea6ab85b06c7e87e", + "url": "https://api.github.com/repos/chrisbliss18/php-ico/zipball/ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6", + "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.2.4" + }, + "type": "library", + "autoload": { + "classmap": [ + "class-php-ico.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "Chris Jean", + "homepage": "https://chrisjean.com", + "role": "Developer" + } + ], + "description": "An easy-to-use library to generate valid ICO files.", + "homepage": "https://github.com/chrisbliss18/php-ico", + "keywords": [ + "favicon", + "ico" + ], + "support": { + "issues": "https://github.com/chrisbliss18/php-ico/issues", + "source": "https://github.com/chrisbliss18/php-ico" + }, + "time": "2016-09-27T22:00:56+00:00" + }, + { + "name": "cocur/slugify", + "version": "v4.7.1", + "source": { + "type": "git", + "url": "https://github.com/cocur/slugify.git", + "reference": "a860dab2b9f5f37775fc6414d4f049434848165f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cocur/slugify/zipball/a860dab2b9f5f37775fc6414d4f049434848165f", + "reference": "a860dab2b9f5f37775fc6414d4f049434848165f", "shasum": "" }, "require": { - "ext-curl": "*", - "ext-intl": "*", - "ext-json": "*", "ext-mbstring": "*", - "kint-php/kint": "^3.3", - "laminas/laminas-escaper": "^2.6", - "php": "^7.3 || ^8.0", - "psr/log": "^1.1" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "conflict": { + "symfony/config": "<3.4 || >=4,<4.3", + "symfony/dependency-injection": "<3.4 || >=4,<4.3", + "symfony/http-kernel": "<3.4 || >=4,<4.3", + "twig/twig": "<2.12.1" }, "require-dev": { - "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "^3.0", - "mikey179/vfsstream": "^1.6", - "nexusphp/cs-config": "^3.1", - "nexusphp/tachycardia": "^1.0", - "phpstan/phpstan": "0.12.88", - "phpunit/phpunit": "^9.1", - "predis/predis": "^1.1", - "rector/rector": "0.11.16", - "symplify/package-builder": "^9.3" + "laravel/framework": "^5.0|^6.0|^7.0|^8.0", + "latte/latte": "~2.2", + "league/container": "^2.2.0", + "mikey179/vfsstream": "~1.6.8", + "mockery/mockery": "^1.3", + "nette/di": "~2.4", + "pimple/pimple": "~1.1", + "plumphp/plum": "~0.1", + "symfony/config": "^3.4 || ^4.3 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^3.4 || ^4.3 || ^5.0 || ^6.0", + "symfony/http-kernel": "^3.4 || ^4.3 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.4 || ^6.0", + "twig/twig": "^2.12.1 || ~3.0", + "zendframework/zend-modulemanager": "~2.2", + "zendframework/zend-servicemanager": "~2.2", + "zendframework/zend-view": "~2.2" }, - "suggest": { - "ext-fileinfo": "Improves mime type detection for files" - }, - "default-branch": true, - "type": "project", - "extra": { - "branch-alias": { - "dev-develop": "4.x-dev" + "type": "library", + "autoload": { + "psr-4": { + "Cocur\\Slugify\\": "src" } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florian Eckerstorfer", + "email": "florian@eckerstorfer.co", + "homepage": "https://florian.ec" + }, + { + "name": "Ivo Bathke", + "email": "ivo.bathke@gmail.com" + } + ], + "description": "Converts a string into a slug.", + "keywords": [ + "slug", + "slugify" + ], + "support": { + "issues": "https://github.com/cocur/slugify/issues", + "source": "https://github.com/cocur/slugify/tree/v4.7.1" + }, + "time": "2025-11-27T18:57:36+00:00" + }, + { + "name": "codeigniter4/framework", + "version": "v4.7.0", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/framework.git", + "reference": "e7753bc03f8b74af428f46b5e2bb74925487c930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/framework/zipball/e7753bc03f8b74af428f46b5e2bb74925487c930", + "reference": "e7753bc03f8b74af428f46b5e2bb74925487c930", + "shasum": "" + }, + "require": { + "ext-intl": "*", + "ext-mbstring": "*", + "laminas/laminas-escaper": "^2.18", + "php": "^8.2", + "psr/log": "^3.0" + }, + "require-dev": { + "codeigniter/coding-standard": "^1.7", + "fakerphp/faker": "^1.24", + "friendsofphp/php-cs-fixer": "^3.47.1", + "kint-php/kint": "^6.1", + "mikey179/vfsstream": "^1.6.12", + "nexusphp/cs-config": "^3.6", + "phpunit/phpunit": "^10.5.16 || ^11.2", + "predis/predis": "^3.0" + }, + "suggest": { + "ext-apcu": "If you use Cache class ApcuHandler", + "ext-curl": "If you use CURLRequest class", + "ext-dom": "If you use TestResponse", + "ext-exif": "If you run Image class tests", + "ext-fileinfo": "Improves mime type detection for files", + "ext-gd": "If you use Image class GDHandler", + "ext-imagick": "If you use Image class ImageMagickHandler", + "ext-libxml": "If you use TestResponse", + "ext-memcache": "If you use Cache class MemcachedHandler with Memcache", + "ext-memcached": "If you use Cache class MemcachedHandler with Memcached", + "ext-mysqli": "If you use MySQL", + "ext-oci8": "If you use Oracle Database", + "ext-pcntl": "If you use Signals", + "ext-pgsql": "If you use PostgreSQL", + "ext-posix": "If you use Signals", + "ext-readline": "Improves CLI::input() usability", + "ext-redis": "If you use Cache class RedisHandler", + "ext-simplexml": "If you format XML", + "ext-sodium": "If you use Encryption SodiumHandler", + "ext-sqlite3": "If you use SQLite3", + "ext-sqlsrv": "If you use SQL Server", + "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" + }, + "type": "project", "autoload": { "psr-4": { "CodeIgniter\\": "system/" }, - "exclude-from-classmap": ["**/Database/Migrations/**"] + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The CodeIgniter framework v4", + "homepage": "https://codeigniter.com", + "support": { + "forum": "https://forum.codeigniter.com/", + "slack": "https://codeigniterchat.slack.com", + "source": "https://github.com/codeigniter4/CodeIgniter4" + }, + "time": "2026-02-01T20:39:35+00:00" + }, + { + "name": "codeigniter4/queue", + "version": "dev-develop", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/queue.git", + "reference": "b44386ad29f0a2124e59582ef5ba170788b926ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/queue/zipball/b44386ad29f0a2124e59582ef5ba170788b926ed", + "reference": "b44386ad29f0a2124e59582ef5ba170788b926ed", + "shasum": "" + }, + "require": { + "php": "^8.2" + }, + "require-dev": { + "codeigniter4/devkit": "^1.3", + "codeigniter4/framework": "^4.3", + "php-amqplib/php-amqplib": "^3.7", + "phpstan/phpstan-strict-rules": "^2.0", + "predis/predis": "^2.0" + }, + "suggest": { + "ext-redis": "If you want to use RedisHandler", + "php-amqplib/php-amqplib": "If you want to use RabbitMQHandler", + "predis/predis": "If you want to use PredisHandler" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "CodeIgniter\\Queue\\": "src" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "michalsn", + "homepage": "https://github.com/michalsn", + "role": "Developer" + } + ], + "description": "Queues for CodeIgniter 4 framework", + "homepage": "https://github.com/codeigniter4/queue", + "keywords": [ + "codeigniter", + "codeigniter4", + "database", + "predis", + "queue", + "redis" + ], + "support": { + "issues": "https://github.com/codeigniter4/queue/issues", + "source": "https://github.com/codeigniter4/queue/tree/develop" + }, + "time": "2026-02-15T08:22:24+00:00" + }, + { + "name": "codeigniter4/settings", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/settings.git", + "reference": "2748f2b4572d44a940f98c31847d65272cac5666" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/settings/zipball/2748f2b4572d44a940f98c31847d65272cac5666", + "reference": "2748f2b4572d44a940f98c31847d65272cac5666", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "codeigniter4/devkit": "^1.1.2", + "codeigniter4/framework": "^4.2.3", + "rector/rector": "0.18.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "CodeIgniter\\Settings\\": "src" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lonnie Ezell", + "email": "lonnieje@gmail.com", + "role": "Developer" + } + ], + "description": "Settings library for CodeIgniter 4", + "homepage": "https://github.com/codeigniter4/settings", + "keywords": [ + "Settings", + "codeigniter", + "codeigniter4" + ], + "support": { + "issues": "https://github.com/codeigniter4/settings/issues", + "source": "https://github.com/codeigniter4/settings/tree/v2.2.0" + }, + "time": "2024-01-06T07:10:58+00:00" + }, + { + "name": "codeigniter4/shield", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/shield.git", + "reference": "2d1b2177a914dcd490f54a6706792eacabd9e3e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/shield/zipball/2d1b2177a914dcd490f54a6706792eacabd9e3e8", + "reference": "2d1b2177a914dcd490f54a6706792eacabd9e3e8", + "shasum": "" + }, + "require": { + "codeigniter4/settings": "^2.1", + "php": "^8.1" + }, + "provide": { + "codeigniter4/authentication-implementation": "1.0" + }, + "require-dev": { + "codeigniter/phpstan-codeigniter": "^1.3", + "codeigniter4/devkit": "^1.3", + "codeigniter4/framework": ">=4.3.5 <4.5.0 || ^4.5.1", + "firebase/php-jwt": "^6.4", + "mikey179/vfsstream": "^1.6.7", + "mockery/mockery": "^1.0", + "phpstan/phpstan-strict-rules": "^2.0" + }, + "suggest": { + "ext-curl": "Required to use the password validation rule via PwnedValidator class.", + "ext-openssl": "Required to use the JWT Authenticator." + }, + "type": "library", + "autoload": { + "psr-4": { + "CodeIgniter\\Shield\\": "src" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lonnie Ezell", + "email": "lonnieje@gmail.com", + "role": "Developer" + } + ], + "description": "Authentication and Authorization for CodeIgniter 4", + "homepage": "https://github.com/codeigniter4/shield", + "keywords": [ + "Authentication", + "authorization", + "codeigniter", + "codeigniter4" + ], + "support": { + "docs": "https://codeigniter4.github.io/shield/", + "forum": "https://github.com/codeigniter4/shield/discussions", + "issues": "https://github.com/codeigniter4/shield/issues", + "slack": "https://codeigniterchat.slack.com", + "source": "https://github.com/codeigniter4/shield" + }, + "time": "2025-07-14T10:26:03+00:00" + }, + { + "name": "codeigniter4/tasks", + "version": "dev-develop", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/tasks.git", + "reference": "8d0c0f83d48dd1ac322d30a4c51ff309ab5368e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/tasks/zipball/8d0c0f83d48dd1ac322d30a4c51ff309ab5368e0", + "reference": "8d0c0f83d48dd1ac322d30a4c51ff309ab5368e0", + "shasum": "" + }, + "require": { + "codeigniter4/queue": "dev-develop", + "codeigniter4/settings": "^2.0", + "ext-json": "*", + "php": "^8.2" + }, + "require-dev": { + "codeigniter4/devkit": "^1.3", + "codeigniter4/framework": "^4.3" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "CodeIgniter\\Tasks\\": "src" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] }, "autoload-dev": { "psr-4": { - "CodeIgniter\\": "tests/system/", - "Utils\\": "utils/" + "Tests\\Support\\": "tests/_support" } }, "scripts": { "post-update-cmd": [ - "CodeIgniter\\ComposerScripts::postUpdate", - "bash -c \"if [ -f admin/setup.sh ]; then bash admin/setup.sh; fi\"" + "bash admin/setup.sh" ], - "analyze": ["phpstan analyse"], - "test": ["phpunit"] + "analyze": [ + "Composer\\Config::disableProcessTimeout", + "phpstan analyze", + "psalm", + "rector process --dry-run" + ], + "sa": [ + "@analyze" + ], + "ci": [ + "Composer\\Config::disableProcessTimeout", + "@cs", + "@deduplicate", + "@inspect", + "@analyze", + "@test" + ], + "cs": [ + "php-cs-fixer fix --ansi --verbose --dry-run --diff" + ], + "cs-fix": [ + "php-cs-fixer fix --ansi --verbose --diff" + ], + "style": [ + "@cs-fix" + ], + "deduplicate": [ + "phpcpd src/ tests/" + ], + "inspect": [ + "deptrac analyze --cache-file=build/deptrac.cache" + ], + "mutate": [ + "infection --threads=2 --skip-initial-tests --coverage=build/phpunit" + ], + "retool": [ + "retool" + ], + "test": [ + "phpunit" + ] }, - "license": ["MIT"], - "description": "The CodeIgniter framework v4", - "homepage": "https://codeigniter.com", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lonnie Ezell", + "email": "lonnieje@gmail.com", + "role": "Developer" + } + ], + "description": "Task Scheduler for CodeIgniter 4", + "homepage": "https://github.com/codeigniter4/tasks", + "keywords": [ + "codeigniter", + "codeigniter4", + "cron", + "task scheduling" + ], "support": { - "forum": "http://forum.codeigniter.com/", - "source": "https://github.com/codeigniter4/CodeIgniter4", - "slack": "https://codeigniterchat.slack.com", - "issues": "https://github.com/codeigniter4/CodeIgniter4/issues" + "source": "https://github.com/codeigniter4/tasks/tree/develop", + "issues": "https://github.com/codeigniter4/tasks/issues" }, - "time": "2021-06-10T06:40:05+00:00" + "time": "2026-02-15T08:22:03+00:00" }, { "name": "composer/ca-bundle", - "version": "1.2.10", + "version": "1.5.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" + "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63", + "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { @@ -174,7 +952,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Jordi Boggiano", @@ -183,11 +963,17 @@ } ], "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", - "keywords": ["cabundle", "cacert", "certificate", "ssl", "tls"], + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.10" + "source": "https://github.com/composer/ca-bundle/tree/1.5.10" }, "funding": [ { @@ -197,212 +983,110 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2021-06-07T13:58:28+00:00" + "time": "2025-12-08T15:06:51+00:00" }, { - "name": "essence/dom", - "version": "1.0.0", + "name": "dflydev/dot-access-data", + "version": "v3.0.3", "source": { "type": "git", - "url": "https://github.com/essence/dom.git", - "reference": "e5776d2286f4ccbd048d160c28ac77ccc6d68f3a" + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/essence/dom/zipball/e5776d2286f4ccbd048d160c28ac77ccc6d68f3a", - "reference": "e5776d2286f4ccbd048d160c28ac77ccc6d68f3a", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Essence\\Dom\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Félix Girault", - "email": "felix.girault@gmail.com", - "homepage": "http://www.felix-girault.fr", - "role": "Developer" - } - ], - "description": "Essence's DOM parser.", - "homepage": "http://github.com/essence/dom", - "keywords": ["dom", "parser"], - "support": { - "issues": "https://github.com/essence/dom/issues", - "source": "https://github.com/essence/dom/tree/1.0.0" - }, - "time": "2015-07-23T20:33:17+00:00" - }, - { - "name": "essence/essence", - "version": "3.5.4", - "source": { - "type": "git", - "url": "https://github.com/essence/essence.git", - "reference": "81e889a87603840dadd04b317a51487df1d45933" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/essence/essence/zipball/81e889a87603840dadd04b317a51487df1d45933", - "reference": "81e889a87603840dadd04b317a51487df1d45933", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", "shasum": "" }, "require": { - "essence/dom": "~1.0.0", - "essence/http": "~1.0.0", - "fg/parkour": "~1.1.0", - "php": ">=5.5.0" - }, - "suggest": { - "ext-curl": "*" - }, - "type": "library", - "autoload": { - "psr-4": { - "Essence\\": "lib/Essence" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-2-Clause"], - "authors": [ - { - "name": "Félix Girault", - "email": "felix.girault@gmail.com", - "homepage": "http://www.felix-girault.fr", - "role": "Developer" - } - ], - "description": "Extracts information about medias on the web, like youtube videos, twitter statuses or blog articles.", - "homepage": "http://github.com/essence/essence", - "keywords": ["embed", "media", "oembed", "opengraph"], - "support": { - "issues": "https://github.com/essence/essence/issues", - "source": "https://github.com/essence/essence/tree/3.5.4" - }, - "time": "2021-01-21T09:58:10+00:00" - }, - { - "name": "essence/http", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/essence/http.git", - "reference": "ce0e52e0c0f2ed894ce2922ab2fd598dcaac91d2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/essence/http/zipball/ce0e52e0c0f2ed894ce2922ab2fd598dcaac91d2", - "reference": "ce0e52e0c0f2ed894ce2922ab2fd598dcaac91d2", - "shasum": "" - }, - "suggest": { - "ext-curl": "*" - }, - "type": "library", - "autoload": { - "psr-4": { - "Essence\\Http\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Félix Girault", - "email": "felix.girault@gmail.com", - "homepage": "http://www.felix-girault.fr", - "role": "Developer" - } - ], - "description": "Essence's HTTP client.", - "homepage": "http://github.com/essence/http", - "keywords": ["client", "http"], - "support": { - "issues": "https://github.com/essence/http/issues", - "source": "https://github.com/essence/http/tree/1.0.0" - }, - "time": "2015-07-23T20:33:50+00:00" - }, - { - "name": "fg/parkour", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/felixgirault/parkour.git", - "reference": "f837eb640fc4aac81b11fe50d2fa04fb4ec71496" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixgirault/parkour/zipball/f837eb640fc4aac81b11fe50d2fa04fb4ec71496", - "reference": "f837eb640fc4aac81b11fe50d2fa04fb4ec71496", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "4.3.*" + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { - "Parkour\\": "lib" + "Dflydev\\DotAccessData\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-2-Clause"], + "license": [ + "MIT" + ], "authors": [ { - "name": "Félix Girault", - "email": "felix.girault@gmail.com", - "homepage": "http://www.felix-girault.fr", - "role": "Developer" + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" } ], - "description": "A collection of utilities to manipulate arrays.", - "homepage": "http://github.com/felixgirault/parkour", - "keywords": ["array", "manipulation", "traversing"], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], "support": { - "issues": "https://github.com/felixgirault/parkour/issues", - "source": "https://github.com/felixgirault/parkour/tree/1.1.1" + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" }, - "time": "2015-10-03T10:39:22+00:00" + "time": "2024-07-08T12:26:09+00:00" }, { "name": "geoip2/geoip2", - "version": "v2.11.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/maxmind/GeoIP2-php.git", - "reference": "d01be5894a5c1a3381c58c9b1795cd07f96c30f7" + "reference": "49fceddd694295e76e970a32848e03bb19e56b42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/d01be5894a5c1a3381c58c9b1795cd07f96c30f7", - "reference": "d01be5894a5c1a3381c58c9b1795cd07f96c30f7", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/49fceddd694295e76e970a32848e03bb19e56b42", + "reference": "49fceddd694295e76e970a32848e03bb19e56b42", "shasum": "" }, "require": { "ext-json": "*", - "maxmind-db/reader": "~1.8", - "maxmind/web-service-common": "~0.8", - "php": ">=7.2" + "maxmind-db/reader": "^1.13.0", + "maxmind/web-service-common": "~0.11", + "php": ">=8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", - "phpunit/phpunit": "^8.0 || ^9.0", - "squizlabs/php_codesniffer": "3.*" + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^10.0", + "squizlabs/php_codesniffer": "4.*" }, "type": "library", "autoload": { @@ -411,7 +1095,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["Apache-2.0"], + "license": [ + "Apache-2.0" + ], "authors": [ { "name": "Gregory J. Oschwald", @@ -421,51 +1107,55 @@ ], "description": "MaxMind GeoIP2 PHP API", "homepage": "https://github.com/maxmind/GeoIP2-php", - "keywords": ["IP", "geoip", "geoip2", "geolocation", "maxmind"], + "keywords": [ + "IP", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], "support": { "issues": "https://github.com/maxmind/GeoIP2-php/issues", - "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.11.0" + "source": "https://github.com/maxmind/GeoIP2-php/tree/v3.3.0" }, - "time": "2020-10-01T18:48:34+00:00" + "time": "2025-11-20T18:50:15+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.0.1", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb", - "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { - "php": "^7.0|^8.0", - "phpoption/phpoption": "^1.7.3" + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "GrahamCampbell\\ResultType\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "An Implementation Of The Result Type", @@ -478,7 +1168,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -490,20 +1180,345 @@ "type": "tidelift" } ], - "time": "2020-04-13T13:17:36+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { - "name": "james-heinrich/getid3", - "version": "2.0.x-dev", + "name": "guzzlehttp/guzzle", + "version": "7.10.0", "source": { "type": "git", - "url": "https://github.com/JamesHeinrich/getID3.git", - "reference": "ee238d552571c6029898b087d5fc95df826418d6" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/ee238d552571c6029898b087d5fc95df826418d6", - "reference": "ee238d552571c6029898b087d5fc95df826418d6", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-08-23T21:21:41+00:00" + }, + { + "name": "james-heinrich/getid3", + "version": "v2.0.0-beta6", + "source": { + "type": "git", + "url": "https://github.com/JamesHeinrich/getID3.git", + "reference": "8bf46222ae008d870e6676b4bf455ed664d90d05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/8bf46222ae008d870e6676b4bf455ed664d90d05", + "reference": "8bf46222ae008d870e6676b4bf455ed664d90d05", "shasum": "" }, "require": { @@ -542,7 +1557,11 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["GPL-1.0-or-later", "LGPL-3.0-only", "MPL-2.0"], + "license": [ + "GPL-1.0-or-later", + "LGPL-3.0-only", + "MPL-2.0" + ], "authors": [ { "name": "James Heinrich", @@ -559,109 +1578,48 @@ ], "description": "Extract and write useful information to/from popular multimedia file formats", "homepage": "https://www.getid3.org/", - "keywords": ["audio", "codecs", "id3", "metadata", "tags", "video"], + "keywords": [ + "audio", + "codecs", + "id3", + "metadata", + "tags", + "video" + ], "support": { "issues": "https://github.com/JamesHeinrich/getID3/issues", - "source": "https://github.com/JamesHeinrich/getID3/tree/2.0" + "source": "https://github.com/JamesHeinrich/getID3/tree/v2.0.0-beta6" }, - "time": "2021-12-15T17:29:14+00:00" - }, - { - "name": "kint-php/kint", - "version": "3.3", - "source": { - "type": "git", - "url": "https://github.com/kint-php/kint.git", - "reference": "335ac1bcaf04d87df70d8aa51e8887ba2c6d203b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kint-php/kint/zipball/335ac1bcaf04d87df70d8aa51e8887ba2c6d203b", - "reference": "335ac1bcaf04d87df70d8aa51e8887ba2c6d203b", - "shasum": "" - }, - "require": { - "php": ">=5.3.6" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", - "phpunit/phpunit": "^4.0", - "seld/phar-utils": "^1.0", - "symfony/finder": "^2.0 || ^3.0 || ^4.0", - "vimeo/psalm": "^3.0" - }, - "suggest": { - "ext-ctype": "Simple data type tests", - "ext-iconv": "Provides fallback detection for ambiguous legacy string encodings such as the Windows and ISO 8859 code pages", - "ext-mbstring": "Provides string encoding detection", - "kint-php/kint-js": "Provides a simplified dump to console.log()", - "kint-php/kint-twig": "Provides d() and s() functions in twig templates", - "symfony/polyfill-ctype": "Replacement for ext-ctype if missing", - "symfony/polyfill-iconv": "Replacement for ext-iconv if missing", - "symfony/polyfill-mbstring": "Replacement for ext-mbstring if missing" - }, - "type": "library", - "autoload": { - "files": ["init.php"], - "psr-4": { - "Kint\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Jonathan Vollebregt", - "homepage": "https://github.com/jnvsor" - }, - { - "name": "Rokas Šleinius", - "homepage": "https://github.com/raveren" - }, - { - "name": "Contributors", - "homepage": "https://github.com/kint-php/kint/graphs/contributors" - } - ], - "description": "Kint - debugging tool for PHP developers", - "homepage": "https://kint-php.github.io/kint/", - "keywords": ["debug", "kint", "php"], - "support": { - "issues": "https://github.com/kint-php/kint/issues", - "source": "https://github.com/kint-php/kint/tree/master" - }, - "time": "2019-10-17T18:05:24+00:00" + "time": "2023-11-02T19:40:57+00:00" }, { "name": "laminas/laminas-escaper", - "version": "2.7.0", + "version": "2.18.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-escaper.git", - "reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5" + "reference": "06f211dfffff18d91844c1f55250d5d13c007e18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/5e04bc5ae5990b17159d79d331055e2c645e5cc5", - "reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/06f211dfffff18d91844c1f55250d5d13c007e18", + "reference": "06f211dfffff18d91844c1f55250d5d13c007e18", "shasum": "" }, "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^7.3 || ~8.0.0" + "ext-ctype": "*", + "ext-mbstring": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, - "replace": { - "zendframework/zend-escaper": "^2.6.1" + "conflict": { + "zendframework/zend-escaper": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~1.0.0", - "phpunit/phpunit": "^9.3", - "psalm/plugin-phpunit": "^0.12.2", - "vimeo/psalm": "^3.16" - }, - "suggest": { - "ext-iconv": "*", - "ext-mbstring": "*" + "infection/infection": "^0.31.0", + "laminas/laminas-coding-standard": "~3.1.0", + "phpunit/phpunit": "^11.5.42", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.13.1" }, "type": "library", "autoload": { @@ -670,10 +1628,15 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", "homepage": "https://laminas.dev", - "keywords": ["escaper", "laminas"], + "keywords": [ + "escaper", + "laminas" + ], "support": { "chat": "https://laminas.dev/chat", "docs": "https://docs.laminas.dev/laminas-escaper/", @@ -688,104 +1651,68 @@ "type": "community_bridge" } ], - "time": "2020-11-17T21:26:43+00:00" - }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6cccbddfcfc742eb02158d6137ca5687d92cee32", - "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", - "psalm/plugin-phpunit": "^0.15.1", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.6" - }, - "type": "library", - "extra": { - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "autoload": { - "files": ["src/autoload.php"], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": ["ZendFramework", "autoloading", "laminas", "zf"], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", - "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", - "source": "https://github.com/laminas/laminas-zendframework-bridge" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-02-25T21:54:58+00:00" + "time": "2025-10-14T18:31:13+00:00" }, { "name": "league/commonmark", - "version": "1.6.2", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb" + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7d70d2f19c84bcc16275ea47edabee24747352eb", - "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "scrutinizer/ocular": "1.7.*" + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "cebe/markdown": "~1.0", - "commonmark/commonmark.js": "0.29.2", - "erusev/parsedown": "~1.0", + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", "ext-json": "*", "github/gfm": "0.29.0", - "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "^1.4", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2", - "scrutinizer/ocular": "^1.5", - "symfony/finder": "^4.2" + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" }, - "bin": ["bin/commonmark"], "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.9-dev" + } + }, "autoload": { "psr-4": { "League\\CommonMark\\": "src" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Colin O'Dell", @@ -794,7 +1721,7 @@ "role": "Lead Developer" } ], - "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", "homepage": "https://commonmark.thephpleague.com", "keywords": [ "commonmark", @@ -808,15 +1735,12 @@ ], "support": { "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", "issues": "https://github.com/thephpleague/commonmark/issues", "rss": "https://github.com/thephpleague/commonmark/releases.atom", "source": "https://github.com/thephpleague/commonmark" }, "funding": [ - { - "url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark", - "type": "custom" - }, { "url": "https://www.colinodell.com/sponsor", "type": "custom" @@ -829,46 +1753,129 @@ "url": "https://github.com/colinodell", "type": "github" }, - { - "url": "https://www.patreon.com/colinodell", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/league/commonmark", "type": "tidelift" } ], - "time": "2021-05-12T11:39:41+00:00" + "time": "2025-11-26T21:48:24+00:00" }, { - "name": "league/html-to-markdown", - "version": "4.10.0", + "name": "league/config", + "version": "v1.2.0", "source": { "type": "git", - "url": "https://github.com/thephpleague/html-to-markdown.git", - "reference": "0868ae7a552e809e5cd8f93ba022071640408e88" + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0868ae7a552e809e5cd8f93ba022071640408e88", - "reference": "0868ae7a552e809e5cd8f93ba022071640408e88", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/html-to-markdown", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/html-to-markdown.git", + "reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0b4066eede55c48f38bcee4fb8f0aa85654390fd", + "reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd", "shasum": "" }, "require": { "ext-dom": "*", "ext-xml": "*", - "php": ">=5.3.3" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "mikehaertl/php-shellcommand": "~1.1.0", - "phpunit/phpunit": "^4.8|^5.7", - "scrutinizer/ocular": "~1.1" + "mikehaertl/php-shellcommand": "^1.1.0", + "phpstan/phpstan": "^1.8.8", + "phpunit/phpunit": "^8.5 || ^9.2", + "scrutinizer/ocular": "^1.6", + "unleashedtech/php-coding-standard": "^2.7 || ^3.0", + "vimeo/psalm": "^4.22 || ^5.0" }, - "bin": ["bin/html-to-markdown"], + "bin": [ + "bin/html-to-markdown" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.10-dev" + "dev-master": "5.2-dev" } }, "autoload": { @@ -877,7 +1884,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Colin O'Dell", @@ -894,10 +1903,13 @@ ], "description": "An HTML-to-markdown conversion helper for PHP", "homepage": "https://github.com/thephpleague/html-to-markdown", - "keywords": ["html", "markdown"], + "keywords": [ + "html", + "markdown" + ], "support": { "issues": "https://github.com/thephpleague/html-to-markdown/issues", - "source": "https://github.com/thephpleague/html-to-markdown/tree/4.10.0" + "source": "https://github.com/thephpleague/html-to-markdown/tree/5.1.1" }, "funding": [ { @@ -913,44 +1925,43 @@ "type": "github" }, { - "url": "https://www.patreon.com/colinodell", - "type": "patreon" + "url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown", + "type": "tidelift" } ], - "time": "2020-07-01T00:34:03+00:00" + "time": "2023-07-12T21:21:09+00:00" }, { "name": "maxmind-db/reader", - "version": "v1.10.1", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "569bd44d97d30a4ec12c7793a33004a76d4caf18" + "reference": "2194f58d0f024ce923e685cdf92af3daf9951908" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/569bd44d97d30a4ec12c7793a33004a76d4caf18", - "reference": "569bd44d97d30a4ec12c7793a33004a76d4caf18", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/2194f58d0f024ce923e685cdf92af3daf9951908", + "reference": "2194f58d0f024ce923e685cdf92af3daf9951908", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "ext-maxminddb": "<1.10.1,>=2.0.0" + "ext-maxminddb": "<1.11.1 || >=2.0.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "php-coveralls/php-coveralls": "^2.1", + "friendsofphp/php-cs-fixer": "3.*", "phpstan/phpstan": "*", - "phpunit/phpcov": ">=6.0.0", "phpunit/phpunit": ">=8.0.0,<10.0.0", - "squizlabs/php_codesniffer": "3.*" + "squizlabs/php_codesniffer": "4.*" }, "suggest": { "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", - "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups", + "maxmind-db/reader-ext": "C extension for significantly faster IP lookups (install via PIE: pie install maxmind-db/reader-ext)" }, "type": "library", "autoload": { @@ -959,7 +1970,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["Apache-2.0"], + "license": [ + "Apache-2.0" + ], "authors": [ { "name": "Gregory J. Oschwald", @@ -969,37 +1982,44 @@ ], "description": "MaxMind DB Reader API", "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", - "keywords": ["database", "geoip", "geoip2", "geolocation", "maxmind"], + "keywords": [ + "database", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], "support": { "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.10.1" + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.13.1" }, - "time": "2021-04-14T17:49:35+00:00" + "time": "2025-11-21T22:24:26+00:00" }, { "name": "maxmind/web-service-common", - "version": "v0.8.1", + "version": "v0.11.1", "source": { "type": "git", "url": "https://github.com/maxmind/web-service-common-php.git", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8" + "reference": "c309236b5a5555b96cf560089ec3cead12d845d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/32f274051c543fc865e5a84d3a2c703913641ea8", - "reference": "32f274051c543fc865e5a84d3a2c703913641ea8", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/c309236b5a5555b96cf560089ec3cead12d845d2", + "reference": "c309236b5a5555b96cf560089ec3cead12d845d2", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0.3", "ext-curl": "*", "ext-json": "*", - "php": ">=7.2" + "php": ">=8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", - "phpunit/phpunit": "^8.0 || ^9.0", - "squizlabs/php_codesniffer": "3.*" + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^10.0", + "squizlabs/php_codesniffer": "4.*" }, "type": "library", "autoload": { @@ -1009,7 +2029,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["Apache-2.0"], + "license": [ + "Apache-2.0" + ], "authors": [ { "name": "Gregory Oschwald", @@ -1020,33 +2042,98 @@ "homepage": "https://github.com/maxmind/web-service-common-php", "support": { "issues": "https://github.com/maxmind/web-service-common-php/issues", - "source": "https://github.com/maxmind/web-service-common-php/tree/v0.8.1" + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.11.1" }, - "time": "2020-11-02T17:00:53+00:00" + "time": "2026-01-13T17:56:03+00:00" }, { - "name": "michalsn/codeigniter4-uuid", - "version": "dev-develop", + "name": "melbahja/seo", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/michalsn/codeigniter4-uuid.git", - "reference": "b26512ac4f3f0c772fbfa2c3317346d3c17e2d44" + "url": "https://github.com/melbahja/seo.git", + "reference": "e8d36b2c46e1b05af957c90beea19090f64d5bf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/michalsn/codeigniter4-uuid/zipball/b26512ac4f3f0c772fbfa2c3317346d3c17e2d44", - "reference": "b26512ac4f3f0c772fbfa2c3317346d3c17e2d44", + "url": "https://api.github.com/repos/melbahja/seo/zipball/e8d36b2c46e1b05af957c90beea19090f64d5bf9", + "reference": "e8d36b2c46e1b05af957c90beea19090f64d5bf9", "shasum": "" }, "require": { - "php": ">=7.3", - "ramsey/uuid": "^4.0" + "ext-curl": "*", + "ext-json": "*", + "ext-xml": "*", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Melbahja\\Seo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mohamed ELbahja", + "email": "mohamed@elbahja.me", + "homepage": "https://elbahja.me", + "role": "Developer" + } + ], + "description": "SEO library for PHP is a simple PHP library to help developers 🍻 do better on-page SEO optimizations.", + "keywords": [ + "images sitemaps", + "index sitemaps", + "meta tags", + "news sitemaps", + "open graph", + "php8", + "rich results", + "schema.org", + "search engine optimization", + "seo", + "sitemap index", + "sitemap.xml", + "sitemaps", + "twitter tags", + "video sitemaps" + ], + "support": { + "issues": "https://github.com/melbahja/seo/issues", + "source": "https://github.com/melbahja/seo/tree/v3.0.2" + }, + "time": "2026-02-08T12:48:54+00:00" + }, + { + "name": "michalsn/codeigniter4-uuid", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/michalsn/codeigniter4-uuid.git", + "reference": "31457ec91f54e3c981762d9f06e87e417869c380" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michalsn/codeigniter4-uuid/zipball/31457ec91f54e3c981762d9f06e87e417869c380", + "reference": "31457ec91f54e3c981762d9f06e87e417869c380", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=8.1", + "ramsey/uuid": "^4.7" }, "require-dev": { "codeigniter4/codeigniter4": "dev-develop", "phpunit/phpunit": "8.5.*" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -1054,7 +2141,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "michalsn", @@ -1064,140 +2153,380 @@ ], "description": "UUID package for CodeIgniter 4 with support for Model and Entity.", "homepage": "https://github.com/michalsn/codeigniter4-uuid", - "keywords": ["codeigniter4", "entity", "model", "uuid"], + "keywords": [ + "codeigniter4", + "entity", + "model", + "uuid" + ], "support": { "issues": "https://github.com/michalsn/codeigniter4-uuid/issues", - "source": "https://github.com/michalsn/codeigniter4-uuid/tree/develop" + "source": "https://github.com/michalsn/codeigniter4-uuid/tree/v1.3.1" }, - "time": "2021-05-10T16:28:01+00:00" + "time": "2025-10-16T10:20:23+00:00" }, { - "name": "myth/auth", - "version": "dev-develop", + "name": "mpratt/embera", + "version": "2.0.42", "source": { "type": "git", - "url": "https://github.com/lonnieezell/myth-auth.git", - "reference": "9bba52bd710a0c35a0b2d8cef64a70706224648a" + "url": "https://github.com/mpratt/Embera.git", + "reference": "afa728339c6f078c803c9277a5054ca241b3c469" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/9bba52bd710a0c35a0b2d8cef64a70706224648a", - "reference": "9bba52bd710a0c35a0b2d8cef64a70706224648a", + "url": "https://api.github.com/repos/mpratt/Embera/zipball/afa728339c6f078c803c9277a5054ca241b3c469", + "reference": "afa728339c6f078c803c9277a5054ca241b3c469", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0" - }, - "provide": { - "codeigniter4/authentication-implementation": "1.0" + "ext-json": "*", + "php": ">=5.6" }, "require-dev": { - "codeigniter4/codeigniter4": "dev-develop", - "codeigniter4/codeigniter4-standard": "^1.0", - "fakerphp/faker": "^1.9", - "mockery/mockery": "^1.0", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.2", - "squizlabs/php_codesniffer": "^3.5" + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.0||^10.0", + "symfony/yaml": "^2.1" + }, + "suggest": { + "ext-curl": "Fetch data using curl instead of using file_get_contents" + }, + "type": "library", + "autoload": { + "psr-4": { + "Embera\\": "src/Embera" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Pratt", + "email": "yo@michael-pratt.com", + "homepage": "http://www.michael-pratt.com", + "role": "Author/Developer" + } + ], + "description": "Oembed consumer library. Converts urls into their html embed code. Supports 150+ sites, such as Youtube, Twitter, vimeo, Instagram etc.", + "homepage": "https://github.com/mpratt/Embera", + "keywords": [ + "Auto embed", + "Embed Text", + "Responsive Embeds", + "Url Embed", + "embed", + "instagram", + "oembed", + "twitter", + "vimeo", + "vine", + "youtube" + ], + "support": { + "issues": "https://github.com/mpratt/Embera/issues", + "source": "https://github.com/mpratt/Embera/tree/2.0.42" + }, + "funding": [ + { + "url": "https://paypal.me/mtpratt", + "type": "paypal" + } + ], + "time": "2025-01-04T06:07:59+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7", + "reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.5" + }, + "require-dev": { + "nette/tester": "^2.6", + "phpstan/phpstan": "^2.0@stable", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.4" + }, + "time": "2026-02-08T02:54:00+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.3" + }, + "time": "2026-02-13T03:05:33+00:00" + }, + { + "name": "opawg/user-agents-v2-php", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/opawg/user-agents-v2-php.git", + "reference": "1b7646bc6e82501c99466fcdef23700604966b97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opawg/user-agents-v2-php/zipball/1b7646bc6e82501c99466fcdef23700604966b97", + "reference": "1b7646bc6e82501c99466fcdef23700604966b97", + "shasum": "" }, "default-branch": true, "type": "library", "autoload": { "psr-4": { - "Myth\\Auth\\": "src" - }, - "exclude-from-classmap": ["**/Database/Migrations/**"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Lonnie Ezell", - "email": "lonnieje@gmail.com", - "homepage": "http://newmythmedia.com", - "role": "Developer" - } - ], - "description": "Flexible authentication/authorization system for CodeIgniter 4.", - "homepage": "https://github.com/lonnieezell/myth-auth", - "keywords": ["Authentication", "authorization", "codeigniter"], - "support": { - "issues": "https://github.com/lonnieezell/myth-auth/issues", - "source": "https://github.com/lonnieezell/myth-auth/tree/v1.0" - }, - "funding": [ - { - "url": "https://github.com/lonnieezell", - "type": "github" - }, - { - "url": "https://www.patreon.com/lonnieezell", - "type": "patreon" - } - ], - "time": "2021-06-10T04:25:01+00:00" - }, - { - "name": "opawg/user-agents-php", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/opawg/user-agents-php.git", - "reference": "e22c7be05f475b44d0e6ecd76acf1617a2efef85" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opawg/user-agents-php/zipball/e22c7be05f475b44d0e6ecd76acf1617a2efef85", - "reference": "e22c7be05f475b44d0e6ecd76acf1617a2efef85", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Opawg\\UserAgentsPhp\\": "src/" + "Opawg\\UserAgentsV2Php\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Benjamin Bellamy", - "email": "ben@podlibre.org", - "homepage": "https://podlibre.org/" + "email": "benjamin@castopod.org", + "homepage": "https://castopod.org/" } ], - "description": "PHP implementation for opawg/user-agents.", - "homepage": "https://github.com/opawg/user-agents-php", + "description": "PHP implementation for opawg/user-agents-v2.", + "homepage": "https://github.com/opawg/user-agents-v2-php", "support": { - "source": "https://github.com/opawg/user-agents-php/tree/v1.0" + "issues": "https://github.com/opawg/user-agents-v2-php/issues", + "source": "https://github.com/opawg/user-agents-v2-php/tree/main" }, - "time": "2020-11-28T10:54:05+00:00" + "time": "2023-12-20T16:54:44+00:00" }, { "name": "phpoption/phpoption", - "version": "1.7.5", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -1206,22 +2535,31 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["Apache-2.0"], + "license": [ + "Apache-2.0" + ], "authors": [ { "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "Option Type for PHP", - "keywords": ["language", "option", "php", "type"], + "keywords": [ + "language", + "option", + "php", + "type" + ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -1233,20 +2571,20 @@ "type": "tidelift" } ], - "time": "2020-07-20T17:29:33+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "phpseclib/phpseclib", - "version": "2.0.31", + "version": "2.0.51", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "233a920cb38636a43b18d428f9a8db1f0a1a08f4" + "reference": "ed661e7cdaeb8c419e609e2f3203551a13c2ed48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/233a920cb38636a43b18d428f9a8db1f0a1a08f4", - "reference": "233a920cb38636a43b18d428f9a8db1f0a1a08f4", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ed661e7cdaeb8c419e609e2f3203551a13c2ed48", + "reference": "ed661e7cdaeb8c419e609e2f3203551a13c2ed48", "shasum": "" }, "require": { @@ -1261,17 +2599,22 @@ "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", - "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "ext-xml": "Install the XML extension to load XML formatted public keys." }, "type": "library", "autoload": { - "files": ["phpseclib/bootstrap.php"], + "files": [ + "phpseclib/bootstrap.php" + ], "psr-4": { "phpseclib\\": "phpseclib/" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Jim Wigginton", @@ -1322,7 +2665,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/2.0.31" + "source": "https://github.com/phpseclib/phpseclib/tree/2.0.51" }, "funding": [ { @@ -1338,87 +2681,24 @@ "type": "tidelift" } ], - "time": "2021-04-06T13:56:45+00:00" - }, - { - "name": "podlibre/ipcat", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/podlibre/ipcat.git", - "reference": "1adfc821be508ddc8a742f6a5d5e6e42fdf28e86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/podlibre/ipcat/zipball/1adfc821be508ddc8a742f6a5d5e6e42fdf28e86", - "reference": "1adfc821be508ddc8a742f6a5d5e6e42fdf28e86", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Podlibre\\Ipcat\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["GPL-3.0-only"], - "authors": [ - { - "name": "Benjamin Bellamy", - "email": "ben@podlibre.org", - "homepage": "https://podlibre.org/" - } - ], - "description": "Categorization of IP Addresses forked from https://github.com/client9/ipcat", - "homepage": "https://github.com/podlibre/ipcat", - "support": { - "source": "https://github.com/podlibre/ipcat/tree/v1.0" - }, - "time": "2020-10-05T17:15:07+00:00" - }, - { - "name": "podlibre/podcast-namespace", - "version": "v1.0.6", - "source": { - "type": "git", - "url": "https://code.podlibre.org/podlibre/podcastnamespace", - "reference": "4525c06ee9dd95bb745ee875d55b64a053c74cd6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Podlibre\\PodcastNamespace\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Benjamin Bellamy", - "email": "ben@podlibre.org", - "homepage": "https://podlibre.org/" - } - ], - "description": "PHP implementation for the Podcast Namespace.", - "homepage": "https://code.podlibre.org/podlibre/podcastnamespace", - "time": "2021-01-14T15:47:06+00:00" + "time": "2026-01-27T09:11:52+00:00" }, { "name": "psr/cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -1432,2312 +2712,25 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", - "keywords": ["cache", "psr", "psr-6"], - "support": { - "source": "https://github.com/php-fig/cache/tree/master" - }, - "time": "2016-08-06T20:24:11+00:00" - }, - { - "name": "psr/log", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": ["log", "psr", "psr-3"], - "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" - }, - "time": "2021-05-03T11:20:27+00:00" - }, - { - "name": "ramsey/collection", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8" - }, - "require-dev": { - "captainhook/captainhook": "^5.3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "ergebnis/composer-normalize": "^2.6", - "fakerphp/faker": "^1.5", - "hamcrest/hamcrest-php": "^2", - "jangregor/phpstan-prophecy": "^0.8", - "mockery/mockery": "^1.3", - "phpstan/extension-installer": "^1", - "phpstan/phpstan": "^0.12.32", - "phpstan/phpstan-mockery": "^0.12.5", - "phpstan/phpstan-phpunit": "^0.12.11", - "phpunit/phpunit": "^8.5 || ^9", - "psy/psysh": "^0.10.4", - "slevomat/coding-standard": "^6.3", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Ramsey\\Collection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", - "keywords": ["array", "collection", "hash", "map", "queue", "set"], - "support": { - "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" - }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", - "type": "tidelift" - } - ], - "time": "2021-01-21T17:40:04+00:00" - }, - { - "name": "ramsey/uuid", - "version": "4.1.1", - "source": { - "type": "git", - "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", - "shasum": "" - }, - "require": { - "brick/math": "^0.8 || ^0.9", - "ext-json": "*", - "php": "^7.2 || ^8", - "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8" - }, - "replace": { - "rhumsaa/uuid": "self.version" - }, - "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", - "doctrine/annotations": "^1.8", - "goaop/framework": "^2", - "mockery/mockery": "^1.3", - "moontoast/math": "^1.1", - "paragonie/random-lib": "^2", - "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", - "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-mockery": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" - }, - "suggest": { - "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", - "ext-ctype": "Enables faster processing of character classification using ctype functions.", - "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", - "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", - "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", - "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Ramsey\\Uuid\\": "src/" - }, - "files": ["src/functions.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", - "keywords": ["guid", "identifier", "uuid"], - "support": { - "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" - }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - } - ], - "time": "2020-08-18T17:17:46+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": ["bootstrap.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": ["compatibility", "ctype", "polyfill", "portable"], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-19T12:13:01+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": ["bootstrap.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": ["compatibility", "mbstring", "polyfill", "portable", "shim"], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-27T09:27:20+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "files": ["bootstrap.php"], - "classmap": ["Resources/stubs"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": ["compatibility", "polyfill", "portable", "shim"], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-19T12:13:01+00:00" - }, - { - "name": "vlucas/phpdotenv", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", - "reference": "b3eac5c7ac896e52deab4a99068e3f4ab12d9e56", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.1", - "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.7.4", - "symfony/polyfill-ctype": "^1.17", - "symfony/polyfill-mbstring": "^1.17", - "symfony/polyfill-php80": "^1.17" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1" - }, - "suggest": { - "ext-filter": "Required to use the boolean validator." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.3-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Graham Campbell", - "email": "graham@alt-three.com", - "homepage": "https://gjcampbell.co.uk/" - }, - { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://vancelucas.com/" - } - ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": ["dotenv", "env", "environment"], - "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2021-01-20T15:23:13+00:00" - }, - { - "name": "whichbrowser/parser", - "version": "v2.1.2", - "source": { - "type": "git", - "url": "https://github.com/WhichBrowser/Parser-PHP.git", - "reference": "bcf642a1891032de16a5ab976fd352753dd7f9a0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/bcf642a1891032de16a5ab976fd352753dd7f9a0", - "reference": "bcf642a1891032de16a5ab976fd352753dd7f9a0", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/cache": "^1.0" - }, - "require-dev": { - "cache/array-adapter": "^1.1", - "icomefromthenet/reverse-regex": "0.0.6.3", - "php-coveralls/php-coveralls": "^2.0", - "phpunit/php-code-coverage": "^5.0 || ^7.0", - "phpunit/phpunit": "^6.0 || ^8.0", - "squizlabs/php_codesniffer": "^3.5", - "symfony/yaml": "~3.4 || ~4.0" - }, - "suggest": { - "cache/array-adapter": "Allows testing of the caching functionality" - }, - "type": "library", - "autoload": { - "psr-4": { - "WhichBrowser\\": ["src/", "tests/src/"] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Niels Leenheer", - "email": "niels@leenheer.nl", - "role": "Developer" - } - ], - "description": "Useragent sniffing library for PHP", - "homepage": "http://whichbrowser.net", - "keywords": ["browser", "sniffing", "ua", "useragent"], - "support": { - "issues": "https://github.com/WhichBrowser/Parser-PHP/issues", - "source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.2" - }, - "time": "2021-05-10T10:18:11+00:00" - } - ], - "packages-dev": [ - { - "name": "captainhook/captainhook", - "version": "5.10.1", - "source": { - "type": "git", - "url": "https://github.com/captainhookphp/captainhook.git", - "reference": "03f31d3c6bdec50c831381f27ecad48c73840726" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/captainhookphp/captainhook/zipball/03f31d3c6bdec50c831381f27ecad48c73840726", - "reference": "03f31d3c6bdec50c831381f27ecad48c73840726", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-spl": "*", - "ext-xml": "*", - "php": ">=7.2", - "sebastianfeldmann/camino": "^0.9.2", - "sebastianfeldmann/cli": "^3.3", - "sebastianfeldmann/git": "^3.7", - "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0", - "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0", - "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" - }, - "replace": { - "sebastianfeldmann/captainhook": "*" - }, - "require-dev": { - "composer/composer": "~1", - "mikey179/vfsstream": "~1" - }, - "bin": ["bin/captainhook"], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0.x-dev" - }, - "captainhook": { - "config": "captainhook.json" - } - }, - "autoload": { - "psr-4": { - "CaptainHook\\App\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Sebastian Feldmann", - "email": "sf@sebastian-feldmann.info" - } - ], - "description": "PHP git hook manager", - "homepage": "https://github.com/captainhookphp/captainhook", "keywords": [ - "commit-msg", - "git", - "hooks", - "post-merge", - "pre-commit", - "pre-push", - "prepare-commit-msg" + "cache", + "psr", + "psr-6" ], "support": { - "issues": "https://github.com/captainhookphp/captainhook/issues", - "source": "https://github.com/captainhookphp/captainhook/tree/5.10.1" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "funding": [ - { - "url": "https://github.com/sponsors/sebastianfeldmann", - "type": "github" - } - ], - "time": "2021-05-25T21:21:59+00:00" - }, - { - "name": "composer/semver", - "version": "3.2.5", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.54", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": ["semantic", "semver", "validation", "versioning"], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-05-24T12:41:47+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": ["Xdebug", "performance"], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.1" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2021-05-05T19:37:51+00:00" - }, - { - "name": "danielstjules/stringy", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/danielstjules/Stringy.git", - "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", - "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "symfony/polyfill-mbstring": "~1.1" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Stringy\\": "src/" - }, - "files": ["src/Create.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Daniel St. Jules", - "email": "danielst.jules@gmail.com", - "homepage": "http://www.danielstjules.com" - } - ], - "description": "A string manipulation library with multibyte support", - "homepage": "https://github.com/danielstjules/Stringy", - "keywords": [ - "UTF", - "helpers", - "manipulation", - "methods", - "multibyte", - "string", - "utf-8", - "utility", - "utils" - ], - "support": { - "issues": "https://github.com/danielstjules/Stringy/issues", - "source": "https://github.com/danielstjules/Stringy" - }, - "time": "2017-06-12T01:10:27+00:00" - }, - { - "name": "doctrine/annotations", - "version": "1.13.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", - "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", - "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": ["annotations", "docblock", "parser"], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.1" - }, - "time": "2021-05-16T18:07:53+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^8.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": ["constructor", "instantiate"], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2020-11-10T18:47:58+00:00" - }, - { - "name": "doctrine/lexer", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": ["annotations", "docblock", "lexer", "parser", "php"], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2020-05-25T17:44:05+00:00" - }, - { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "c15377bdfa8d1ecf186f1deadec39c89984e1167" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/c15377bdfa8d1ecf186f1deadec39c89984e1167", - "reference": "c15377bdfa8d1ecf186f1deadec39c89984e1167", - "shasum": "" - }, - "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^2.0", - "doctrine/annotations": "^1.12", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^7.1.3 || ^8.0", - "php-cs-fixer/diff": "^2.0", - "symfony/console": "^4.4.20 || ^5.1.3", - "symfony/event-dispatcher": "^4.4.20 || ^5.0", - "symfony/filesystem": "^4.4.20 || ^5.0", - "symfony/finder": "^4.4.20 || ^5.0", - "symfony/options-resolver": "^4.4.20 || ^5.0", - "symfony/polyfill-php72": "^1.22", - "symfony/process": "^4.4.20 || ^5.0", - "symfony/stopwatch": "^4.4.20 || ^5.0" - }, - "require-dev": { - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^1.4", - "mikey179/vfsstream": "^1.6.8", - "php-coveralls/php-coveralls": "^2.4.3", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.10.3", - "phpspec/prophecy-phpunit": "^1.1 || ^2.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5", - "phpunitgoodpractices/polyfill": "^1.5", - "phpunitgoodpractices/traits": "^1.9.1", - "symfony/phpunit-bridge": "^5.2.4", - "symfony/yaml": "^4.4.20 || ^5.0" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters.", - "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." - }, - "bin": ["php-cs-fixer"], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.0.0" - }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2021-05-03T21:51:58+00:00" - }, - { - "name": "mikey179/vfsstream", - "version": "v1.6.8", - "source": { - "type": "git", - "url": "https://github.com/bovigo/vfsStream.git", - "reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/231c73783ebb7dd9ec77916c10037eff5a2b6efe", - "reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "org\\bovigo\\vfs\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Frank Kleine", - "homepage": "http://frankkleine.de/", - "role": "Developer" - } - ], - "description": "Virtual file system to mock the real file system in unit tests.", - "homepage": "http://vfs.bovigo.org/", - "support": { - "issues": "https://github.com/bovigo/vfsStream/issues", - "source": "https://github.com/bovigo/vfsStream/tree/master", - "wiki": "https://github.com/bovigo/vfsStream/wiki" - }, - "time": "2019-10-30T15:31:00+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.10.2", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": ["src/DeepCopy/deep_copy.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Create deep copies (clones) of your objects", - "keywords": ["clone", "copy", "duplicate", "object", "object graph"], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2020-11-13T09:40:50+00:00" - }, - { - "name": "nette/neon", - "version": "v3.2.2", - "source": { - "type": "git", - "url": "https://github.com/nette/neon.git", - "reference": "e4ca6f4669121ca6876b1d048c612480e39a28d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/neon/zipball/e4ca6f4669121ca6876b1d048c612480e39a28d5", - "reference": "e4ca6f4669121ca6876b1d048c612480e39a28d5", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=7.1" - }, - "require-dev": { - "nette/tester": "^2.0", - "phpstan/phpstan": "^0.12", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "🍸 Nette NEON: encodes and decodes NEON file format.", - "homepage": "https://ne-on.org", - "keywords": ["export", "import", "neon", "nette", "yaml"], - "support": { - "issues": "https://github.com/nette/neon/issues", - "source": "https://github.com/nette/neon/tree/v3.2.2" - }, - "time": "2021-02-28T12:30:32+00:00" - }, - { - "name": "nette/utils", - "version": "v3.2.2", - "source": { - "type": "git", - "url": "https://github.com/nette/utils.git", - "reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/967cfc4f9a1acd5f1058d76715a424c53343c20c", - "reference": "967cfc4f9a1acd5f1058d76715a424c53343c20c", - "shasum": "" - }, - "require": { - "php": ">=7.2 <8.1" - }, - "conflict": { - "nette/di": "<3.0.6" - }, - "require-dev": { - "nette/tester": "~2.0", - "phpstan/phpstan": "^0.12", - "tracy/tracy": "^2.3" - }, - "suggest": { - "ext-gd": "to use Image", - "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", - "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", - "ext-json": "to use Nette\\Utils\\Json", - "ext-mbstring": "to use Strings::lower() etc...", - "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", - "ext-xml": "to use Strings::length() etc. when mbstring is not available" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", - "homepage": "https://nette.org", - "keywords": [ - "array", - "core", - "datetime", - "images", - "json", - "nette", - "paginator", - "password", - "slugify", - "string", - "unicode", - "utf-8", - "utility", - "validation" - ], - "support": { - "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v3.2.2" - }, - "time": "2021-03-03T22:53:25+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.10.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": ["bin/php-parse"], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": ["parser", "php"], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" - }, - "time": "2021-05-03T19:11:20+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" - }, - "time": "2020-06-27T14:33:11+00:00" - }, - { - "name": "phar-io/version", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" - }, - "time": "2021-02-23T14:00:09+00:00" - }, - { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", - "source": { - "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" - }, - "type": "library", - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", - "keywords": ["diff"], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" - }, - "time": "2020-10-14T08:32:19+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" - }, - "time": "2020-09-03T19:13:55+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" - }, - "time": "2020-09-17T18:55:26+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.13.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": ["Double", "Dummy", "fake", "mock", "spy", "stub"], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" - }, - "time": "2021-03-17T13:42:18+00:00" - }, - { - "name": "phpstan/extension-installer", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/66c7adc9dfa38b6b5838a9fb728b68a7d8348051", - "reference": "66c7adc9dfa38b6b5838a9fb728b68a7d8348051", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1 || ^2.0", - "php": "^7.1 || ^8.0", - "phpstan/phpstan": ">=0.11.6" - }, - "require-dev": { - "composer/composer": "^1.8", - "phing/phing": "^2.16.3", - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpstan/phpstan-strict-rules": "^0.11 || ^0.12" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPStan\\ExtensionInstaller\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPStan\\ExtensionInstaller\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Composer plugin for automatic installation of PHPStan extensions", - "support": { - "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.1.0" - }, - "time": "2020-12-13T13:06:13+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "phing/phing": "^2.16.3", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.60", - "phpstan/phpstan-strict-rules": "^0.12.5", - "phpunit/phpunit": "^7.5.20", - "symfony/process": "^5.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5-dev" - } - }, - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": ["src/"] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.4" - }, - "time": "2021-04-03T14:46:19+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "0.12.88", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/464d1a81af49409c41074aa6640ed0c4cbd9bb68", - "reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": ["phpstan", "phpstan.phar"], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.12-dev" - } - }, - "autoload": { - "files": ["bootstrap.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "PHPStan - PHP Static Analysis Tool", - "support": { - "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.88" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" - } - ], - "time": "2021-05-17T12:24:49+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": ["coverage", "testing", "xunit"], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-03-28T07:26:59+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": ["filesystem", "iterator"], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:57:25+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": ["process"], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": ["template"], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": ["timer"], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.5.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/89ff45ea9d70e35522fb6654a2ebc221158de276", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.3.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.2", - "sebastian/version": "^3.0.2" - }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" - }, - "bin": ["phpunit"], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.5-dev" - } - }, - "autoload": { - "classmap": ["src/"], - "files": ["src/Framework/Assert/Functions.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": ["phpunit", "testing", "xunit"], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.5" - }, - "funding": [ - { - "url": "https://phpunit.de/donate.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-06-05T04:49:07+00:00" - }, - { - "name": "psr/container", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" - }, - "time": "2021-03-05T17:36:06+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/event-dispatcher", @@ -3768,7 +2761,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "PHP-FIG", @@ -3776,7 +2771,11 @@ } ], "description": "Standard interfaces for event handling.", - "keywords": ["events", "psr", "psr-14"], + "keywords": [ + "events", + "psr", + "psr-14" + ], "support": { "issues": "https://github.com/php-fig/event-dispatcher/issues", "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" @@ -3784,50 +2783,3391 @@ "time": "2019-01-08T18:20:26+00:00" }, { - "name": "rector/rector", - "version": "0.11.16", + "name": "psr/http-client", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "5c030ad7cefa59075e0fe14604cd4982ceaa2bd0" + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/5c030ad7cefa59075e0fe14604cd4982ceaa2bd0", - "reference": "5c030ad7cefa59075e0fe14604cd4982ceaa2bd0", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { - "php": "^7.1|^8.0", - "phpstan/phpstan": ">=0.12.86 <=0.12.88" + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" }, - "conflict": { - "phpstan/phpdoc-parser": "<=0.5.3", - "phpstan/phpstan": "<=0.12.82", - "rector/rector-cakephp": "*", - "rector/rector-doctrine": "*", - "rector/rector-nette": "*", - "rector/rector-nette-to-symfony": "*", - "rector/rector-phpunit": "*", - "rector/rector-prefixed": "*", - "rector/rector-symfony": "*" - }, - "bin": ["bin/rector"], "type": "library", "extra": { "branch-alias": { - "dev-main": "0.10-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "files": ["bootstrap.php"] + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Prefixed and PHP 7.1 downgraded version of rector/rector", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.9.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "8429c78ca35a09f27565311b98101e2826affde0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.25", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.9.2" + }, + "time": "2025-12-14T04:43:48+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v8.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "d937d400b980523dc9ee946bb69972b5e619058d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d", + "reference": "d937d400b980523dc9ee946bb69972b5e619058d", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v8.0.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-12-01T09:13:36+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" + }, + { + "name": "whichbrowser/parser", + "version": "v2.1.8", + "source": { + "type": "git", + "url": "https://github.com/WhichBrowser/Parser-PHP.git", + "reference": "581d614d686bfbec3529ad60562a5213ac5d8d72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/581d614d686bfbec3529ad60562a5213ac5d8d72", + "reference": "581d614d686bfbec3529ad60562a5213ac5d8d72", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "cache/array-adapter": "^1.1", + "icomefromthenet/reverse-regex": "0.0.6.3", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/php-code-coverage": "^5.0 || ^7.0", + "phpunit/phpunit": "^6.0 || ^8.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/yaml": "~3.4 || ~4.0" + }, + "suggest": { + "cache/array-adapter": "Allows testing of the caching functionality" + }, + "type": "library", + "autoload": { + "psr-4": { + "WhichBrowser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niels Leenheer", + "email": "niels@leenheer.nl", + "role": "Developer" + } + ], + "description": "Useragent sniffing library for PHP", + "homepage": "http://whichbrowser.net", + "keywords": [ + "browser", + "sniffing", + "ua", + "useragent" + ], + "support": { + "issues": "https://github.com/WhichBrowser/Parser-PHP/issues", + "source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.8" + }, + "time": "2024-04-17T12:47:41+00:00" + }, + { + "name": "yassinedoghri/codeigniter-vite", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/yassinedoghri/codeigniter-vite.git", + "reference": "95c1dd30b716e3204ce981aa564202b299f9c8a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yassinedoghri/codeigniter-vite/zipball/95c1dd30b716e3204ce981aa564202b299f9c8a5", + "reference": "95c1dd30b716e3204ce981aa564202b299f9c8a5", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "codeigniter/phpstan-codeigniter": "^1.5.4", + "codeigniter4/framework": "^v4.6.0", + "pestphp/pest": "^3.8.4", + "pestphp/pest-plugin-type-coverage": "^3.6.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "rector/rector": "^2.1.4", + "symplify/coding-standard": "^12.4.3", + "symplify/easy-coding-standard": "^12.5.24" + }, + "type": "library", + "autoload": { + "psr-4": { + "CodeIgniterVite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Yassine Doghri", + "homepage": "https://yassinedoghri.com/" + } + ], + "description": "An opinionated Vite integration for CodeIgniter4 projects.", + "keywords": [ + "codeigniter", + "codeigniter4", + "iconify", + "icons", + "php-icons" + ], + "support": { + "issues": "https://github.com/yassinedoghri/codeigniter-vite/issues", + "source": "https://github.com/yassinedoghri/codeigniter-vite/tree/v2.1.0" + }, + "time": "2025-09-09T18:36:45+00:00" + }, + { + "name": "yassinedoghri/php-icons", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/yassinedoghri/php-icons.git", + "reference": "ae5d7727431f6891a0660d2b20818795fae40b41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yassinedoghri/php-icons/zipball/ae5d7727431f6891a0660d2b20818795fae40b41", + "reference": "ae5d7727431f6891a0660d2b20818795fae40b41", + "shasum": "" + }, + "require": { + "adhocore/cli": "^v1.9.3", + "composer-runtime-api": "^2.2", + "php": ">=8.1" + }, + "require-dev": { + "kint-php/kint": "^6.0.1", + "pestphp/pest": "^3.7.4", + "pestphp/pest-plugin-type-coverage": "^3.4.0", + "phpstan/phpstan": "^2.1.10", + "rector/rector": "^2.0.10", + "symplify/coding-standard": "^12.2.3", + "symplify/easy-coding-standard": "^12.5.9" + }, + "bin": [ + "bin/php-icons" + ], + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Console/helpers.php" + ], + "psr-4": { + "PHPIcons\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Yassine Doghri", + "email": "yassine@doghri.fr", + "homepage": "https://yassinedoghri.com", + "role": "Maintainer" + } + ], + "description": "A PHP library based on iconify's API to download and render svg icons from popular open source icon sets.", + "support": { + "issues": "https://github.com/yassinedoghri/php-icons/issues", + "source": "https://github.com/yassinedoghri/php-icons/tree/v1.3.0" + }, + "time": "2025-03-23T16:46:25+00:00" + }, + { + "name": "yassinedoghri/podcast-feed", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/yassinedoghri/podcast-feed.git", + "reference": "d617e204fe85e0b7bd12b9d382cae4064af280c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yassinedoghri/podcast-feed/zipball/d617e204fe85e0b7bd12b9d382cae4064af280c8", + "reference": "d617e204fe85e0b7bd12b9d382cae4064af280c8", + "shasum": "" + }, + "require": { + "ext-intl": "*", + "php": ">=8.1" + }, + "require-dev": { + "kint-php/kint": "^5.0.5", + "phpstan/phpstan": "^1.10.18", + "rector/rector": "^0.17.0", + "symplify/coding-standard": "^11.3.0", + "symplify/easy-coding-standard": "^11.3.4" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "PodcastFeed\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Yassine Doghri", + "email": "yassine@doghri.fr", + "homepage": "https://yassinedoghri.com", + "role": "Maintainer" + } + ], + "description": "A robust podcast feed parser and validator written in PHP.", + "support": { + "issues": "https://github.com/yassinedoghri/podcast-feed/issues", + "source": "https://github.com/yassinedoghri/podcast-feed/tree/main" + }, + "time": "2024-04-28T16:17:41+00:00" + }, + { + "name": "z4kn4fein/php-semver", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/z4kn4fein/php-semver.git", + "reference": "049a1d81e92235c8b3c9ab30a96fcbaa929a266d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/z4kn4fein/php-semver/zipball/049a1d81e92235c8b3c9ab30a96fcbaa929a266d", + "reference": "049a1d81e92235c8b3c9ab30a96fcbaa929a266d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^10" + }, + "type": "library", + "autoload": { + "psr-4": { + "z4kn4fein\\SemVer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Csajtai", + "email": "peter.csajtai@outlook.com" + } + ], + "description": "Semantic Versioning library for PHP. It implements the full semantic version 2.0.0 specification and provides ability to parse, compare, and increment semantic versions along with validation against constraints.", + "homepage": "https://github.com/z4kn4fein/php-semver", + "keywords": [ + "comparison", + "semantic", + "semver", + "validation", + "version", + "versioning" + ], + "support": { + "issues": "https://github.com/z4kn4fein/php-semver/issues", + "source": "https://github.com/z4kn4fein/php-semver/tree/v3.0.0" + }, + "time": "2024-04-01T16:17:27+00:00" + } + ], + "packages-dev": [ + { + "name": "captainhook/captainhook", + "version": "5.28.3", + "source": { + "type": "git", + "url": "https://github.com/captainhook-git/captainhook.git", + "reference": "5d35b249f3843ef36ead119f4347e649278ad6d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/5d35b249f3843ef36ead119f4347e649278ad6d8", + "reference": "5d35b249f3843ef36ead119f4347e649278ad6d8", + "shasum": "" + }, + "require": { + "captainhook/secrets": "^0.9.4", + "ext-json": "*", + "ext-spl": "*", + "ext-xml": "*", + "php": ">=8.0", + "sebastianfeldmann/camino": "^0.9.2", + "sebastianfeldmann/cli": "^3.3", + "sebastianfeldmann/git": "^3.16.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + }, + "replace": { + "sebastianfeldmann/captainhook": "*" + }, + "require-dev": { + "composer/composer": "~1 || ^2.0", + "mikey179/vfsstream": "~1" + }, + "bin": [ + "bin/captainhook" + ], + "type": "library", + "extra": { + "captainhook": { + "config": "captainhook.json" + }, + "branch-alias": { + "dev-main": "6.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "CaptainHook\\App\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "PHP git hook manager", + "homepage": "https://php.captainhook.info/", + "keywords": [ + "commit-msg", + "git", + "hooks", + "post-merge", + "pre-commit", + "pre-push", + "prepare-commit-msg" + ], + "support": { + "issues": "https://github.com/captainhook-git/captainhook/issues", + "source": "https://github.com/captainhook-git/captainhook/tree/5.28.3" + }, + "funding": [ + { + "url": "https://github.com/sponsors/sebastianfeldmann", + "type": "github" + } + ], + "time": "2026-02-16T14:08:58+00:00" + }, + { + "name": "captainhook/secrets", + "version": "0.9.7", + "source": { + "type": "git", + "url": "https://github.com/captainhook-git/secrets.git", + "reference": "d62c97f75f81ac98e22f1c282482bd35fa82f631" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/captainhook-git/secrets/zipball/d62c97f75f81ac98e22f1c282482bd35fa82f631", + "reference": "d62c97f75f81ac98e22f1c282482bd35fa82f631", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CaptainHook\\Secrets\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian Feldmann", + "email": "sf@sebastian-feldmann.info" + } + ], + "description": "Utility classes to detect secrets", + "keywords": [ + "commit-msg", + "keys", + "passwords", + "post-merge", + "prepare-commit-msg", + "secrets", + "tokens" + ], + "support": { + "issues": "https://github.com/captainhook-git/secrets/issues", + "source": "https://github.com/captainhook-git/secrets/tree/0.9.7" + }, + "funding": [ + { + "url": "https://github.com/sponsors/sebastianfeldmann", + "type": "github" + } + ], + "time": "2025-04-08T07:10:48+00:00" + }, + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, + { + "name": "codeigniter/phpstan-codeigniter", + "version": "v1.5.4", + "source": { + "type": "git", + "url": "https://github.com/CodeIgniter/phpstan-codeigniter.git", + "reference": "e959fb0841c29a01870aa6570f3095f42e1057ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CodeIgniter/phpstan-codeigniter/zipball/e959fb0841c29a01870aa6570f3095f42e1057ad", + "reference": "e959fb0841c29a01870aa6570f3095f42e1057ad", + "shasum": "" + }, + "require": { + "php": "^8.1", + "phpstan/phpstan": "^2.0" + }, + "conflict": { + "codeigniter/framework": "*" + }, + "require-dev": { + "codeigniter/coding-standard": "^1.7", + "codeigniter4/framework": "^4.5", + "codeigniter4/shield": "^1.0", + "friendsofphp/php-cs-fixer": "^3.49", + "nexusphp/cs-config": "^3.21", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^10.5 || ^11.4" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "CodeIgniter\\PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Paul E. Balandan, CPA", + "email": "paulbalandan@gmail.com" + } + ], + "description": "CodeIgniter extensions and rules for PHPStan", + "keywords": [ + "PHPStan", + "codeigniter", + "codeigniter4", + "dev", + "static analysis" + ], + "support": { + "forum": "http://forum.codeigniter.com/", + "issues": "https://github.com/CodeIgniter/phpstan-codeigniter/issues", + "slack": "https://codeigniterchat.slack.com", + "source": "https://github.com/CodeIgniter/phpstan-codeigniter" + }, + "time": "2025-06-24T17:28:48+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-08-20T19:15:30+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2025-08-14T07:29:31+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.94.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d1a3634e29916367b885250e1fc4dfd5ffe3b091", + "reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091", + "shasum": "" + }, + "require": { + "clue/ndjson-react": "^1.3", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.5", + "ext-filter": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.3", + "php": "^7.4 || ^8.0", + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0", + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.33", + "symfony/polyfill-php80": "^1.33", + "symfony/polyfill-php81": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" + }, + "require-dev": { + "facile-it/paraunit": "^1.3.1 || ^2.7.1", + "infection/infection": "^0.32.3", + "justinrainbow/json-schema": "^6.6.4", + "keradus/cli-executor": "^2.3", + "mikey179/vfsstream": "^1.6.12", + "php-coveralls/php-coveralls": "^2.9.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7", + "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51", + "symfony/polyfill-php85": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "exclude-from-classmap": [ + "src/**/Internal/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.1" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2026-02-18T12:24:42+00:00" + }, + { + "name": "mikey179/vfsstream", + "version": "v1.6.12", + "source": { + "type": "git", + "url": "https://github.com/bovigo/vfsStream.git", + "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/fe695ec993e0a55c3abdda10a9364eb31c6f1bf0", + "reference": "fe695ec993e0a55c3abdda10a9364eb31c6f1bf0", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5||^8.5||^9.6", + "yoast/phpunit-polyfills": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "org\\bovigo\\vfs\\": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Frank Kleine", + "homepage": "http://frankkleine.de/", + "role": "Developer" + } + ], + "description": "Virtual file system to mock the real file system in unit tests.", + "homepage": "http://vfs.bovigo.org/", + "support": { + "issues": "https://github.com/bovigo/vfsStream/issues", + "source": "https://github.com/bovigo/vfsStream/tree/master", + "wiki": "https://github.com/bovigo/vfsStream/wiki" + }, + "time": "2024-08-29T18:43:31+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.39", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", + "reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-02-11T14:48:56+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "13.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "a8b58fde2f4fbc69a064e1f80ff917607cf7737c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a8b58fde2f4fbc69a064e1f80ff917607cf7737c", + "reference": "a8b58fde2f4fbc69a064e1f80ff917607cf7737c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.4", + "phpunit/php-file-iterator": "^7.0", + "phpunit/php-text-template": "^6.0", + "sebastian/complexity": "^6.0", + "sebastian/environment": "^9.0", + "sebastian/lines-of-code": "^5.0", + "sebastian/version": "^7.0", + "theseer/tokenizer": "^2.0.1" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "13.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/13.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2026-02-06T06:05:15+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:33:26+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^13.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-invoker", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:34:47+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/a47af19f93f76aa3368303d752aa5272ca3299f4", + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-text-template", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:36:37+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/a0e12065831f6ab0d83120dc61513eb8d9a966f6", + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/9.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-timer", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:37:53+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "13.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "d57826e8921a534680c613924bfd921ded8047f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d57826e8921a534680c613924bfd921ded8047f4", + "reference": "d57826e8921a534680c613924bfd921ded8047f4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.4.1", + "phpunit/php-code-coverage": "^13.0.1", + "phpunit/php-file-iterator": "^7.0.0", + "phpunit/php-invoker": "^7.0.0", + "phpunit/php-text-template": "^6.0.0", + "phpunit/php-timer": "^9.0.0", + "sebastian/cli-parser": "^5.0.0", + "sebastian/comparator": "^8.0.0", + "sebastian/diff": "^8.0.0", + "sebastian/environment": "^9.0.0", + "sebastian/exporter": "^8.0.0", + "sebastian/global-state": "^9.0.0", + "sebastian/object-enumerator": "^8.0.0", + "sebastian/recursion-context": "^8.0.0", + "sebastian/type": "^7.0.0", + "sebastian/version": "^7.0.0", + "staabm/side-effects-detector": "^1.0.5" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "13.0-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/13.0.5" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-02-18T12:40:03+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.7", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/socket": "^1.16", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.7" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-12-23T15:25:20+00:00" + }, + { + "name": "react/dns", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.14.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-18T19:34:28+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-17T20:46:25+00:00" + }, + { + "name": "react/promise", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.12.28 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-08-19T18:57:03+00:00" + }, + { + "name": "react/socket", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.17.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-19T20:47:34+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, + { + "name": "rector/rector", + "version": "2.3.6", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/ca9ebb81d280cd362ea39474dabd42679e32ca6b", + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.38" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/0.11.16" + "source": "https://github.com/rectorphp/rector/tree/2.3.6" }, "funding": [ { @@ -3835,85 +6175,43 @@ "type": "github" } ], - "time": "2021-06-08T08:41:04+00:00" - }, - { - "name": "rector/rector-phpstan-rules", - "version": "0.2.12", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/phpstan-rules.git", - "reference": "84b2034aab951be7e86dc6cc7e141ee92a3d115b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/phpstan-rules/zipball/84b2034aab951be7e86dc6cc7e141ee92a3d115b", - "reference": "84b2034aab951be7e86dc6cc7e141ee92a3d115b", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "php": ">=7.3", - "phpstan/phpstan": "^0.12.86", - "symplify/phpstan-rules": "^9.3.5" - }, - "require-dev": { - "phpstan/extension-installer": "^1.1", - "phpunit/phpunit": "^9.5", - "symplify/easy-coding-standard": "^9.3", - "symplify/phpstan-extensions": "^9.3" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": ["config/config.neon"] - } - }, - "autoload": { - "psr-4": { - "Rector\\PHPStanRules\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "PHPStan rules for Rector projects - with focus on static reflection, constant re-use and Rector design patterns", - "support": { - "issues": "https://github.com/rectorphp/phpstan-rules/issues", - "source": "https://github.com/rectorphp/phpstan-rules/tree/0.2.12" - }, - "time": "2021-05-20T22:31:19+00:00" + "time": "2026-02-06T14:25:06+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/48a4654fa5e48c1c81214e9930048a572d4b23ca", + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -3925,152 +6223,71 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/5.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2026-02-06T04:39:44+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "29b232ddc29c2b114c0358c69b3084e7c3da0d58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/29b232ddc29c2b114c0358c69b3084e7c3da0d58", + "reference": "29b232ddc29c2b114c0358c69b3084e7c3da0d58", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.4", + "sebastian/diff": "^8.0", + "sebastian/exporter": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4091,51 +6308,72 @@ ], "description": "Provides the functionality to compare PHP values for equality", "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": ["comparator", "compare", "equality"], + "keywords": [ + "comparator", + "compare", + "equality" + ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2026-02-06T04:40:39+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "c5651c795c98093480df79350cb050813fc7a2f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c5651c795c98093480df79350cb050813fc7a2f3", + "reference": "c5651c795c98093480df79350cb050813fc7a2f3", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" + "nikic/php-parser": "^5.0", + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4147,48 +6385,65 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/6.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/complexity", + "type": "tidelift" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2026-02-06T04:41:32+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a2b6d09d7729ee87d605a439469f9dcc39be5ea3", + "reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^13.0", + "symfony/process": "^7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4201,38 +6456,56 @@ ], "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": ["diff", "udiff", "unidiff", "unified diff"], + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/diff", + "type": "tidelift" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2026-02-06T04:42:27+00:00" }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "9.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "bb64d08145b021b67d5f253308a498b73ab0461e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/bb64d08145b021b67d5f253308a498b73ab0461e", + "reference": "bb64d08145b021b67d5f253308a498b73ab0461e", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "suggest": { "ext-posix": "*" @@ -4240,14 +6513,18 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "9.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4255,53 +6532,74 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": ["Xdebug", "environment", "hhvm"], + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/9.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2026-02-06T04:43:29+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea", + "reference": "dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.4", + "sebastian/recursion-context": "^8.0" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4325,57 +6623,74 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": ["export", "exporter"], + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2026-02-06T04:44:28+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "9.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "e52e3dc22441e6218c710afe72c3042f8fc41ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e52e3dc22441e6218c710afe72c3042f8fc41ea7", + "reference": "e52e3dc22441e6218c710afe72c3042f8fc41ea7", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "9.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4383,52 +6698,71 @@ } ], "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": ["global state"], + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/9.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2020-10-26T15:55:19+00:00" + "time": "2026-02-06T04:45:13+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "4f21bb7768e1c997722ccc7efb1d6b5c11bfd471" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/4f21bb7768e1c997722ccc7efb1d6b5c11bfd471", + "reference": "4f21bb7768e1c997722ccc7efb1d6b5c11bfd471", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" + "nikic/php-parser": "^5.0", + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4440,49 +6774,66 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/5.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code", + "type": "tidelift" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2026-02-06T04:45:54+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4493,47 +6844,64 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-enumerator", + "type": "tidelift" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2026-02-06T04:46:36+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4544,47 +6912,64 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/6.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-reflector", + "type": "tidelift" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2026-02-06T04:47:13+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/74c5af21f6a5833e91767ca068c4d3dfec15317e", + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4600,101 +6985,67 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/8.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" - } - ], - "time": "2020-10-26T13:17:30+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": ["src/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], - "authors": [ + }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" - }, - "funding": [ + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2026-02-06T04:51:28+00:00" }, { "name": "sebastian/type", - "version": "2.3.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1" + "reference": "42412224607bd3931241bbd17f38e0f972f5a916" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0d1c587401514d17e8f9258a27e23527cb1b06c1", - "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/42412224607bd3931241bbd17f38e0f972f5a916", + "reference": "42412224607bd3931241bbd17f38e0f972f5a916", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^13.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4706,44 +7057,61 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.2" + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/7.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2021-06-04T13:02:07+00:00" + "time": "2026-02-06T04:52:09+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ad37a5552c8e2b88572249fdc19b6da7792e021b", + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Sebastian Bergmann", @@ -4755,28 +7123,41 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/7.0.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/version", + "type": "tidelift" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2026-02-06T04:52:52+00:00" }, { "name": "sebastianfeldmann/camino", - "version": "0.9.4", + "version": "0.9.5", "source": { "type": "git", "url": "https://github.com/sebastianfeldmann/camino.git", - "reference": "3b611368e22e8565c3a6504613136402ed9e6f69" + "reference": "bf2e4c8b2a029e9eade43666132b61331e3e8184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianfeldmann/camino/zipball/3b611368e22e8565c3a6504613136402ed9e6f69", - "reference": "3b611368e22e8565c3a6504613136402ed9e6f69", + "url": "https://api.github.com/repos/sebastianfeldmann/camino/zipball/bf2e4c8b2a029e9eade43666132b61331e3e8184", + "reference": "bf2e4c8b2a029e9eade43666132b61331e3e8184", "shasum": "" }, "require": { @@ -4794,7 +7175,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Sebastian Feldmann", @@ -4803,10 +7186,13 @@ ], "description": "Path management the OO way", "homepage": "https://github.com/sebastianfeldmann/camino", - "keywords": ["file system", "path"], + "keywords": [ + "file system", + "path" + ], "support": { "issues": "https://github.com/sebastianfeldmann/camino/issues", - "source": "https://github.com/sebastianfeldmann/camino/tree/0.9.4" + "source": "https://github.com/sebastianfeldmann/camino/tree/0.9.5" }, "funding": [ { @@ -4814,20 +7200,20 @@ "type": "github" } ], - "time": "2020-12-08T09:25:24+00:00" + "time": "2022-01-03T13:15:10+00:00" }, { "name": "sebastianfeldmann/cli", - "version": "3.3.3", + "version": "3.4.2", "source": { "type": "git", "url": "https://github.com/sebastianfeldmann/cli.git", - "reference": "c4a677f229976c88cc8f50b1477ab15244a4f6d8" + "reference": "6fa122afd528dae7d7ec988a604aa6c600f5d9b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianfeldmann/cli/zipball/c4a677f229976c88cc8f50b1477ab15244a4f6d8", - "reference": "c4a677f229976c88cc8f50b1477ab15244a4f6d8", + "url": "https://api.github.com/repos/sebastianfeldmann/cli/zipball/6fa122afd528dae7d7ec988a604aa6c600f5d9b5", + "reference": "6fa122afd528dae7d7ec988a604aa6c600f5d9b5", "shasum": "" }, "require": { @@ -4848,7 +7234,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Sebastian Feldmann", @@ -4857,10 +7245,12 @@ ], "description": "PHP cli helper classes", "homepage": "https://github.com/sebastianfeldmann/cli", - "keywords": ["cli"], + "keywords": [ + "cli" + ], "support": { "issues": "https://github.com/sebastianfeldmann/cli/issues", - "source": "https://github.com/sebastianfeldmann/cli/tree/3.3.3" + "source": "https://github.com/sebastianfeldmann/cli/tree/3.4.2" }, "funding": [ { @@ -4868,28 +7258,32 @@ "type": "github" } ], - "time": "2021-06-03T16:02:45+00:00" + "time": "2024-11-26T10:19:01+00:00" }, { "name": "sebastianfeldmann/git", - "version": "3.7.1", + "version": "3.16.0", "source": { "type": "git", "url": "https://github.com/sebastianfeldmann/git.git", - "reference": "406b98e09c37249ce586be8ed5766bf0ca389490" + "reference": "40a5cc043f0957228767f639e370ec92590e940f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/406b98e09c37249ce586be8ed5766bf0ca389490", - "reference": "406b98e09c37249ce586be8ed5766bf0ca389490", + "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/40a5cc043f0957228767f639e370ec92590e940f", + "reference": "40a5cc043f0957228767f639e370ec92590e940f", "shasum": "" }, "require": { "ext-json": "*", - "ext-xml": "*", - "php": ">=7.2", + "ext-libxml": "*", + "ext-simplexml": "*", + "php": ">=8.0", "sebastianfeldmann/cli": "^3.0" }, + "require-dev": { + "mikey179/vfsstream": "^1.6" + }, "type": "library", "extra": { "branch-alias": { @@ -4902,7 +7296,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Sebastian Feldmann", @@ -4911,10 +7307,12 @@ ], "description": "PHP git wrapper", "homepage": "https://github.com/sebastianfeldmann/git", - "keywords": ["git"], + "keywords": [ + "git" + ], "support": { "issues": "https://github.com/sebastianfeldmann/git/issues", - "source": "https://github.com/sebastianfeldmann/git/tree/3.7.1" + "source": "https://github.com/sebastianfeldmann/git/tree/3.16.0" }, "funding": [ { @@ -4922,140 +7320,109 @@ "type": "github" } ], - "time": "2021-05-29T12:47:08+00:00" + "time": "2026-01-26T20:59:18+00:00" }, { - "name": "symfony/config", - "version": "v5.3.0", + "name": "staabm/side-effects-detector", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810" + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9f4a448c2d7fd2c90882dfff930b627ddbe16810", - "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/polyfill-php81": "^1.22" - }, - "conflict": { - "symfony/finder": "<4.4" + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": ["/Tests/"] + "classmap": [ + "lib/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" ], - "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", - "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.3.0" + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/staabm", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2024-10-20T05:08:20+00:00" }, { "name": "symfony/console", - "version": "v5.3.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "058553870f7809087fa80fa734704a21b9bcaeb2" + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/058553870f7809087fa80fa734704a21b9bcaeb2", - "reference": "058553870f7809087fa80fa734704a21b9bcaeb2", + "url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b", + "reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" - }, - "conflict": { - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.4|^8.0" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -5068,9 +7435,14 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", - "keywords": ["cli", "command line", "console", "terminal"], + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.0" + "source": "https://github.com/symfony/console/tree/v8.0.4" }, "funding": [ { @@ -5082,87 +7454,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T17:43:10+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/94d973cb742d8c5c5dcf9534220e6b73b09af1d4", - "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1.6|^2" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<5.3", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4" - }, - "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0|2.0" - }, - "require-dev": { - "symfony/config": "^5.3", - "symfony/expression-language": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows you to standardize and centralize the way objects are constructed in your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -5170,186 +7462,58 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:57:12+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": ["function.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-03-23T23:28:01+00:00" - }, - { - "name": "symfony/error-handler", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/error-handler.git", - "reference": "0e6768b8c0dcef26df087df2bbbaa143867a59b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/0e6768b8c0dcef26df087df2bbbaa143867a59b2", - "reference": "0e6768b8c0dcef26df087df2bbbaa143867a59b2", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/log": "^1.0", - "symfony/polyfill-php80": "^1.15", - "symfony/var-dumper": "^4.4|^5.0" - }, - "require-dev": { - "symfony/deprecation-contracts": "^2.1", - "symfony/http-kernel": "^4.4|^5.0", - "symfony/serializer": "^4.4|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\ErrorHandler\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools to manage errors and ease debugging PHP code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2026-01-13T13:06:50+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.3.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce" + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67a5f354afa8e2f231081b3fa11a5912f933c3ce", - "reference": "67a5f354afa8e2f231081b3fa11a5912f933c3ce", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/event-dispatcher-contracts": "^2", - "symfony/polyfill-php80": "^1.15" + "php": ">=8.4", + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<4.4" + "symfony/security-http": "<7.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/error-handler": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/http-foundation": "^4.4|^5.0", - "symfony/service-contracts": "^1.1|^2", - "symfony/stopwatch": "^4.4|^5.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -5363,7 +7527,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.3.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4" }, "funding": [ { @@ -5374,42 +7538,43 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2026-01-05T11:45:55+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.4.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/69fee1ad2332a7cbab3aca13591953da9cdb7a11", - "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -5418,7 +7583,9 @@ } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -5440,7 +7607,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -5456,92 +7623,41 @@ "type": "tidelift" } ], - "time": "2021-03-23T23:28:01+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "348116319d7fb7d1faa781d26a48922428013eb2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/348116319d7fb7d1faa781d26a48922428013eb2", - "reference": "348116319d7fb7d1faa781d26a48922428013eb2", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/finder", - "version": "v5.3.0", + "version": "v8.0.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0", + "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=8.4" + }, + "require-dev": { + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -5555,7 +7671,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.0" + "source": "https://github.com/symfony/finder/tree/v8.0.5" }, "funding": [ { @@ -5567,79 +7683,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T12:52:38+00:00" - }, - { - "name": "symfony/http-client-contracts", - "version": "v2.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/7e82f6084d7cae521a75ef2cb5c9457bbda785f4", - "reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4", - "shasum": "" - }, - "require": { - "php": ">=7.2.5" - }, - "suggest": { - "symfony/http-client-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\HttpClient\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to HTTP clients", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v2.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -5647,214 +7691,39 @@ "type": "tidelift" } ], - "time": "2021-04-11T23:07:08+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v5.3.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "8827b90cf8806e467124ad476acd15216c2fceb6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/8827b90cf8806e467124ad476acd15216c2fceb6", - "reference": "8827b90cf8806e467124ad476acd15216c2fceb6", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" - }, - "require-dev": { - "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/mime": "^4.4|^5.0" - }, - "suggest": { - "symfony/mime": "To use the file extension guesser" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Defines an object-oriented layer for the HTTP specification", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-06-02T09:32:00+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v5.3.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "74eb022e3bac36b3d3a897951a98759f2b32b864" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/74eb022e3bac36b3d3a897951a98759f2b32b864", - "reference": "74eb022e3bac36b3d3a897951a98759f2b32b864", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/log": "~1.0", - "symfony/deprecation-contracts": "^2.1", - "symfony/error-handler": "^4.4|^5.0", - "symfony/event-dispatcher": "^5.0", - "symfony/http-client-contracts": "^1.1|^2", - "symfony/http-foundation": "^5.3", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.15" - }, - "conflict": { - "symfony/browser-kit": "<4.4", - "symfony/cache": "<5.0", - "symfony/config": "<5.0", - "symfony/console": "<4.4", - "symfony/dependency-injection": "<5.3", - "symfony/doctrine-bridge": "<5.0", - "symfony/form": "<5.0", - "symfony/http-client": "<5.0", - "symfony/mailer": "<5.0", - "symfony/messenger": "<5.0", - "symfony/translation": "<5.0", - "symfony/twig-bridge": "<5.0", - "symfony/validator": "<5.0", - "twig/twig": "<2.13" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^4.4|^5.0", - "symfony/config": "^5.0", - "symfony/console": "^4.4|^5.0", - "symfony/css-selector": "^4.4|^5.0", - "symfony/dependency-injection": "^5.3", - "symfony/dom-crawler": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/routing": "^4.4|^5.0", - "symfony/stopwatch": "^4.4|^5.0", - "symfony/translation": "^4.4|^5.0", - "symfony/translation-contracts": "^1.1|^2", - "twig/twig": "^2.13|^3.0.4" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a structured process for converting a Request into a Response", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.3.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-06-02T10:07:12+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.3.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "162e886ca035869866d233a2bfef70cc28f9bbe5" + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/162e886ca035869866d233a2bfef70cc28f9bbe5", - "reference": "162e886ca035869866d233a2bfef70cc28f9bbe5", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7", + "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.15" + "php": ">=8.4", + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -5867,9 +7736,13 @@ ], "description": "Provides an improved replacement for the array_replace PHP function", "homepage": "https://symfony.com", - "keywords": ["config", "configuration", "options"], + "keywords": [ + "config", + "configuration", + "options" + ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.3.0" + "source": "https://github.com/symfony/options-resolver/tree/v8.0.0" }, "funding": [ { @@ -5880,51 +7753,56 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2025-11-12T15:55:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/24b72c6baa32c746a4d0840147c9715e42bb68ab", - "reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, - "files": ["bootstrap.php"] + } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -5946,7 +7824,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5957,52 +7835,59 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, - "files": ["bootstrap.php"], - "classmap": ["Resources/stubs"] + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -6024,7 +7909,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -6036,70 +7921,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-19T12:13:01+00:00" - }, - { - "name": "symfony/polyfill-php72", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, - "files": ["bootstrap.php"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": ["compatibility", "polyfill", "portable", "shim"], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -6107,112 +7929,47 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": ["bootstrap.php"], - "classmap": ["Resources/stubs"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": ["compatibility", "polyfill", "portable", "shim"], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.23.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "e66119f3de95efc359483f810c4c3e6436279436" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", - "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { "Symfony\\Polyfill\\Php81\\": "" }, - "files": ["bootstrap.php"], - "classmap": ["Resources/stubs"] + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -6225,9 +7982,14 @@ ], "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", "homepage": "https://symfony.com", - "keywords": ["compatibility", "polyfill", "portable", "shim"], + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -6238,40 +8000,127 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-21T13:25:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/process", - "version": "v5.3.0", + "name": "symfony/polyfill-php84", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "53e36cb1c160505cdaf1ef201501669c4c317191" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/53e36cb1c160505cdaf1ef201501669c4c317191", - "reference": "53e36cb1c160505cdaf1ef201501669c4c317191", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.15" + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-24T13:30:11+00:00" + }, + { + "name": "symfony/process", + "version": "v8.0.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674", + "shasum": "" + }, + "require": { + "php": ">=8.4" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -6285,7 +8134,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.3.0" + "source": "https://github.com/symfony/process/tree/v8.0.5" }, "funding": [ { @@ -6296,51 +8145,61 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-26T12:52:38+00:00" + "time": "2026-01-26T15:08:38+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.4.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", - "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, - "suggest": { - "symfony/service-implementation": "" + "conflict": { + "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -6362,7 +8221,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -6373,40 +8232,48 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-04-01T10:43:52+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.3.0", + "version": "v8.0.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65" + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/313d02f59d6543311865007e5ff4ace05b35ee65", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/67df1914c6ccd2d7b52f70d40cf2aea02159d942", + "reference": "67df1914c6ccd2d7b52f70d40cf2aea02159d942", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1.0|^2" + "php": ">=8.4", + "symfony/service-contracts": "^2.5|^3" }, "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" }, - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Fabien Potencier", @@ -6420,7 +8287,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v8.0.0" }, "funding": [ { @@ -6431,51 +8298,64 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2025-08-04T07:36:47+00:00" }, { "name": "symfony/string", - "version": "v5.3.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "a9a0f8b6aafc5d2d1c116dcccd1573a95153515b" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a9a0f8b6aafc5d2d1c116dcccd1573a95153515b", - "reference": "a9a0f8b6aafc5d2d1c116dcccd1573a95153515b", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Symfony\\Component\\String\\": "" }, - "files": ["Resources/functions.php"], - "exclude-from-classmap": ["/Tests/"] + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "authors": [ { "name": "Nicolas Grekas", @@ -6488,9 +8368,16 @@ ], "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", "homepage": "https://symfony.com", - "keywords": ["grapheme", "i18n", "string", "unicode", "utf-8", "utf8"], + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.0" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -6502,80 +8389,7 @@ "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T17:43:10+00:00" - }, - { - "name": "symfony/var-dumper", - "version": "v5.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "1d3953e627fe4b5f6df503f356b6545ada6351f3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1d3953e627fe4b5f6df503f356b6545ada6351f3", - "reference": "1d3953e627fe4b5f6df503f356b6545ada6351f3", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" - }, - "conflict": { - "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" - }, - "require-dev": { - "ext-iconv": "*", - "symfony/console": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "twig/twig": "^2.13|^3.0.4" - }, - "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, - "bin": ["Resources/bin/var-dump-server"], - "type": "library", - "autoload": { - "files": ["Resources/functions/dump.php"], - "psr-4": { - "Symfony\\Component\\VarDumper\\": "" - }, - "exclude-from-classmap": ["/Tests/"] - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides mechanisms for walking through any arbitrary PHP variable", - "homepage": "https://symfony.com", - "keywords": ["debug", "dump"], - "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/nicolas-grekas", "type": "github" }, { @@ -6583,166 +8397,53 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:28:50+00:00" - }, - { - "name": "symplify/astral", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/astral.git", - "reference": "2d205265eacad08eb5b620ddfa71b334ce992233" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/astral/zipball/2d205265eacad08eb5b620ddfa71b334ce992233", - "reference": "2d205265eacad08eb5b620ddfa71b334ce992233", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "nikic/php-parser": "4.10.5", - "php": ">=7.3", - "symfony/dependency-injection": "^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/autowire-array-parameter": "^9.3.22", - "symplify/package-builder": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5", - "symplify/easy-testing": "^9.3.22" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\Astral\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Toolking for smart daily work with AST", - "support": { - "source": "https://github.com/symplify/astral/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T09:28:23+00:00" - }, - { - "name": "symplify/autowire-array-parameter", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/autowire-array-parameter.git", - "reference": "7794f4d1eafa7e32905e8b38d37eae7b597ed1a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/autowire-array-parameter/zipball/7794f4d1eafa7e32905e8b38d37eae7b597ed1a8", - "reference": "7794f4d1eafa7e32905e8b38d37eae7b597ed1a8", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "php": ">=7.3", - "symfony/dependency-injection": "^5.2", - "symplify/package-builder": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\AutowireArrayParameter\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Autowire array parameters for your Symfony applications", - "support": { - "source": "https://github.com/symplify/autowire-array-parameter/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T09:28:28+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symplify/coding-standard", - "version": "v9.3.22", + "version": "13.0.0", "source": { "type": "git", "url": "https://github.com/symplify/coding-standard.git", - "reference": "3ce70069790d35e6d6377675778157b573f3a2dd" + "reference": "bd7c36af1e96eecd08cfcc0a772a19767aa02300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/coding-standard/zipball/3ce70069790d35e6d6377675778157b573f3a2dd", - "reference": "3ce70069790d35e6d6377675778157b573f3a2dd", + "url": "https://api.github.com/repos/symplify/coding-standard/zipball/bd7c36af1e96eecd08cfcc0a772a19767aa02300", + "reference": "bd7c36af1e96eecd08cfcc0a772a19767aa02300", "shasum": "" }, "require": { - "friendsofphp/php-cs-fixer": "^3.0", - "nette/utils": "^3.2", - "php": ">=7.3", - "symplify/autowire-array-parameter": "^9.3.22", - "symplify/package-builder": "^9.3.22", - "symplify/rule-doc-generator-contracts": "^9.3.22", - "symplify/symplify-kernel": "^9.3.22" + "friendsofphp/php-cs-fixer": "^3.89", + "nette/utils": "^4.0", + "php": ">=8.2" }, "require-dev": { - "doctrine/orm": "^2.7", - "nette/application": "^3.1", - "nette/bootstrap": "^3.1", - "phpunit/phpunit": "^9.5", - "symfony/framework-bundle": "^4.4|^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/easy-coding-standard": "^9.3.22", - "symplify/rule-doc-generator": "^9.3.22", - "symplify/smart-file-system": "^9.3.22" + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.5|^12.0", + "rector/jack": "^0.2", + "rector/rector": "^2.2", + "squizlabs/php_codesniffer": "^4.0", + "symplify/easy-coding-standard": "^12.6", + "symplify/phpstan-extensions": "^12.0", + "tomasvotruba/class-leak": "^2.0", + "tracy/tracy": "^2.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, "autoload": { "psr-4": { "Symplify\\CodingStandard\\": "src" } }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], + "license": [ + "MIT" + ], "description": "Set of Symplify rules for PHP_CodeSniffer and PHP CS Fixer.", "support": { - "source": "https://github.com/symplify/coding-standard/tree/v9.3.22" + "issues": "https://github.com/symplify/coding-standard/issues", + "source": "https://github.com/symplify/coding-standard/tree/13.0.0" }, "funding": [ { @@ -6754,139 +8455,56 @@ "type": "github" } ], - "time": "2021-06-10T09:28:27+00:00" - }, - { - "name": "symplify/composer-json-manipulator", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/composer-json-manipulator.git", - "reference": "a3d711ec0928cf8ddf3e4c16dad335318d588679" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/composer-json-manipulator/zipball/a3d711ec0928cf8ddf3e4c16dad335318d588679", - "reference": "a3d711ec0928cf8ddf3e4c16dad335318d588679", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "php": ">=7.3", - "symfony/config": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/filesystem": "^4.4|^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/package-builder": "^9.3.22", - "symplify/smart-file-system": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\ComposerJsonManipulator\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Package to load, merge and save composer.json file(s)", - "support": { - "source": "https://github.com/symplify/composer-json-manipulator/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T09:28:23+00:00" - }, - { - "name": "symplify/console-package-builder", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/console-package-builder.git", - "reference": "14a0eeaed45b850e579ddd16913a5d74ec856f16" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/console-package-builder/zipball/14a0eeaed45b850e579ddd16913a5d74ec856f16", - "reference": "14a0eeaed45b850e579ddd16913a5d74ec856f16", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "symfony/console": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symplify/symplify-kernel": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/package-builder": "^9.3.22" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\ConsolePackageBuilder\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Package to speed up building command line applications", - "support": { - "source": "https://github.com/symplify/console-package-builder/tree/v9.3.22" - }, - "time": "2021-06-10T09:28:40+00:00" + "time": "2025-10-30T21:46:47+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "v9.3.22", + "version": "13.0.4", "source": { "type": "git", - "url": "https://github.com/symplify/easy-coding-standard.git", - "reference": "7ada08f221241f513531588585e55f423100705d" + "url": "https://github.com/easy-coding-standard/easy-coding-standard.git", + "reference": "5c7e7a07e5d6a98b9dd2e6fc0a9155efb7c166c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/7ada08f221241f513531588585e55f423100705d", - "reference": "7ada08f221241f513531588585e55f423100705d", + "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/5c7e7a07e5d6a98b9dd2e6fc0a9155efb7c166c8", + "reference": "5c7e7a07e5d6a98b9dd2e6fc0a9155efb7c166c8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "conflict": { - "friendsofphp/php-cs-fixer": "<3.0", - "squizlabs/php_codesniffer": "<3.6" + "friendsofphp/php-cs-fixer": "<3.92.4", + "phpcsstandards/php_codesniffer": "<4.0.1", + "symplify/coding-standard": "<12.1" }, - "bin": ["bin/ecs"], + "suggest": { + "ext-dom": "Needed to support checkstyle output format in class CheckstyleOutputFormatter" + }, + "bin": [ + "bin/ecs" + ], "type": "library", "autoload": { - "files": ["bootstrap.php"] + "files": [ + "bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Prefixed scoped version of ECS package", + "license": [ + "MIT" + ], + "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer", + "keywords": [ + "Code style", + "automation", + "fixer", + "static analysis" + ], "support": { - "source": "https://github.com/symplify/easy-coding-standard/tree/v9.3.22" + "issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues", + "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/13.0.4" }, "funding": [ { @@ -6898,486 +8516,38 @@ "type": "github" } ], - "time": "2021-06-10T09:29:11+00:00" - }, - { - "name": "symplify/easy-testing", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/easy-testing.git", - "reference": "6d5543190c9d578b61d9181d77d7255340743929" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/easy-testing/zipball/6d5543190c9d578b61d9181d77d7255340743929", - "reference": "6d5543190c9d578b61d9181d77d7255340743929", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "php": ">=7.3", - "symfony/console": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/finder": "^4.4|^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/console-package-builder": "^9.3.22", - "symplify/package-builder": "^9.3.22", - "symplify/smart-file-system": "^9.3.22", - "symplify/symplify-kernel": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "bin": ["bin/easy-testing"], - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\EasyTesting\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Testing made easy", - "support": { - "source": "https://github.com/symplify/easy-testing/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T09:28:48+00:00" - }, - { - "name": "symplify/package-builder", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/symplify/package-builder.git", - "reference": "a86c7bd0307ba0b368510851e86082f773e64138" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/package-builder/zipball/a86c7bd0307ba0b368510851e86082f773e64138", - "reference": "a86c7bd0307ba0b368510851e86082f773e64138", - "shasum": "" - }, - "require": { - "nette/neon": "^3.2", - "nette/utils": "^3.2", - "php": ">=7.3", - "symfony/config": "^4.4|^5.2", - "symfony/console": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/finder": "^4.4|^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/easy-testing": "^9.3.22", - "symplify/symplify-kernel": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\PackageBuilder\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Dependency Injection, Console and Kernel toolkit for Symplify packages.", - "support": { - "source": "https://github.com/symplify/package-builder/tree/main" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T09:30:06+00:00" - }, - { - "name": "symplify/phpstan-extensions", - "version": "v9.3.21", - "source": { - "type": "git", - "url": "https://github.com/symplify/phpstan-extensions.git", - "reference": "e9c83ac50fe205f28bece8013d92f5a9130dc3d6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/phpstan-extensions/zipball/e9c83ac50fe205f28bece8013d92f5a9130dc3d6", - "reference": "e9c83ac50fe205f28bece8013d92f5a9130dc3d6", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "phpstan/phpstan": "^0.12.88", - "symplify/astral": "^9.3.21", - "symplify/package-builder": "^9.3.21", - "symplify/smart-file-system": "^9.3.21" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "phpstan-extension", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - }, - "phpstan": { - "includes": ["config/config.neon"] - } - }, - "autoload": { - "psr-4": { - "Symplify\\PHPStanExtensions\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Pre-escaped error messages in 'symplify' error format, container aware test case and other useful extensions for PHPStan", - "support": { - "source": "https://github.com/symplify/phpstan-extensions/tree/v9.3.21" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T08:50:09+00:00" - }, - { - "name": "symplify/phpstan-rules", - "version": "v9.3.21", - "source": { - "type": "git", - "url": "https://github.com/symplify/phpstan-rules.git", - "reference": "1fac85aa8621e29af083b49c71d8ce793ca4dd46" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/1fac85aa8621e29af083b49c71d8ce793ca4dd46", - "reference": "1fac85aa8621e29af083b49c71d8ce793ca4dd46", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "nikic/php-parser": "4.10.5", - "php": ">=7.3", - "phpstan/phpdoc-parser": "^0.5", - "phpstan/phpstan": "^0.12.88", - "symplify/astral": "^9.3.21", - "symplify/composer-json-manipulator": "^9.3.21", - "symplify/package-builder": "^9.3.21", - "symplify/rule-doc-generator-contracts": "^9.3.21", - "symplify/simple-php-doc-parser": "^9.3.21", - "symplify/smart-file-system": "^9.3.21", - "webmozart/assert": "^1.9" - }, - "require-dev": { - "nette/application": "^3.1", - "nette/forms": "^3.1", - "phpunit/phpunit": "^9.5", - "symfony/framework-bundle": "^4.4|^5.2", - "symplify/easy-testing": "^9.3.21", - "symplify/phpstan-extensions": "^9.3.21", - "symplify/rule-doc-generator": "^9.3.21" - }, - "type": "phpstan-extension", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - }, - "phpstan": { - "includes": [ - "config/services/services.neon", - "packages/cognitive-complexity/config/cognitive-complexity-services.neon", - "packages/object-calisthenics/config/object-calisthenics-services.neon" - ] - } - }, - "autoload": { - "psr-4": { - "Symplify\\PHPStanRules\\": "src", - "Symplify\\PHPStanRules\\CognitiveComplexity\\": "packages/cognitive-complexity/src", - "Symplify\\PHPStanRules\\ObjectCalisthenics\\": "packages/object-calisthenics/src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Set of Symplify rules for PHPStan", - "support": { - "source": "https://github.com/symplify/phpstan-rules/tree/v9.3.21" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T08:50:10+00:00" - }, - { - "name": "symplify/rule-doc-generator-contracts", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/rule-doc-generator-contracts.git", - "reference": "a6f944a49198ed3260bc941533629e917137e476" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/rule-doc-generator-contracts/zipball/a6f944a49198ed3260bc941533629e917137e476", - "reference": "a6f944a49198ed3260bc941533629e917137e476", - "shasum": "" - }, - "require": { - "danielstjules/stringy": "^3.1", - "nette/utils": "^3.2", - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\RuleDocGenerator\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Contracts for production code of RuleDocGenerator", - "support": { - "source": "https://github.com/symplify/rule-doc-generator-contracts/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-06T16:17:29+00:00" - }, - { - "name": "symplify/simple-php-doc-parser", - "version": "v9.3.21", - "source": { - "type": "git", - "url": "https://github.com/symplify/simple-php-doc-parser.git", - "reference": "5668608067a6ee4f0513348bdb46319617288ce1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/simple-php-doc-parser/zipball/5668608067a6ee4f0513348bdb46319617288ce1", - "reference": "5668608067a6ee4f0513348bdb46319617288ce1", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "phpstan/phpdoc-parser": "^0.5", - "symfony/config": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/package-builder": "^9.3.21" - }, - "require-dev": { - "phpunit/phpunit": "^9.5", - "symplify/easy-testing": "^9.3.21" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\SimplePhpDocParser\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Service integration of phpstan/phpdoc-parser, with few extra goodies for practical simple use", - "support": { - "source": "https://github.com/symplify/simple-php-doc-parser/tree/v9.3.21" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-06-10T08:50:34+00:00" - }, - { - "name": "symplify/smart-file-system", - "version": "v9.3.22", - "source": { - "type": "git", - "url": "https://github.com/symplify/smart-file-system.git", - "reference": "a2a8d39fe46b01ead8d2af7368b0b36b68fac979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/smart-file-system/zipball/a2a8d39fe46b01ead8d2af7368b0b36b68fac979", - "reference": "a2a8d39fe46b01ead8d2af7368b0b36b68fac979", - "shasum": "" - }, - "require": { - "nette/utils": "^3.2", - "php": ">=7.3", - "symfony/filesystem": "^4.4|^5.2", - "symfony/finder": "^4.4|^5.2" - }, - "require-dev": { - "nette/finder": "^2.5", - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\SmartFileSystem\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Sanitized FileInfo with safe getRealPath() and other handy methods", - "support": { - "source": "https://github.com/symplify/smart-file-system/tree/v9.3.22" - }, - "funding": [ - { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" - }, - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2021-05-20T20:16:49+00:00" - }, - { - "name": "symplify/symplify-kernel", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/symplify/symplify-kernel.git", - "reference": "966602555962ef929214be2459bfeef3d0ceb114" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symplify/symplify-kernel/zipball/966602555962ef929214be2459bfeef3d0ceb114", - "reference": "966602555962ef929214be2459bfeef3d0ceb114", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "symfony/console": "^4.4|^5.2", - "symfony/dependency-injection": "^5.2", - "symfony/http-kernel": "^4.4|^5.2", - "symplify/autowire-array-parameter": "^9.3.22", - "symplify/composer-json-manipulator": "^9.3.22", - "symplify/package-builder": "^9.3.22", - "symplify/smart-file-system": "^9.3.22" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symplify\\SymplifyKernel\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "description": "Internal Kernel for Symplify packages", - "support": { - "source": "https://github.com/symplify/symplify-kernel/tree/main" - }, - "time": "2021-06-10T09:29:50+00:00" + "time": "2026-01-05T09:10:04+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.1" }, "type": "library", "autoload": { - "classmap": ["src/"] + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", - "license": ["BSD-3-Clause"], + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Arne Blankerts", @@ -7388,7 +8558,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" }, "funding": [ { @@ -7396,74 +8566,22 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": ["MIT"], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": ["assert", "check", "validate"], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2025-12-08T11:19:18+00:00" } ], "aliases": [], "minimum-stability": "dev", "stability-flags": { - "james-heinrich/getid3": 20, - "myth/auth": 20, - "codeigniter4/codeigniter4": 20, - "michalsn/codeigniter4-uuid": 20 + "adaures/castopod-plugins-manager": 20, + "codeigniter4/tasks": 20, + "opawg/user-agents-v2-php": 20, + "yassinedoghri/podcast-feed": 20 }, "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.0" + "php": "^8.4" }, - "platform-dev": [], - "plugin-api-version": "2.1.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/crontab b/crontab deleted file mode 100644 index fc44ff63..00000000 --- a/crontab +++ /dev/null @@ -1 +0,0 @@ -* * * * * /usr/local/bin/php /castopod/public/index.php scheduled-activities diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..944c6241 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,8 @@ +commit_message: "[ci skip]" +files: + - source: /app/Language/en/*.php + translation: /app/Language/%osx_locale%/%original_file_name% + - source: /modules/**/Language/en/*.php + translation: /modules/**/Language/%osx_locale%/%original_file_name% + - source: /docs/src/content/docs/en/**/*.mdx + translation: /docs/src/content/docs/%osx_locale%/**/%original_file_name% diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 4142285e..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,66 +0,0 @@ -version: "3" - -networks: - castopod: - -services: - app: - build: - context: . - dockerfile: Dockerfile - container_name: castopod-host - command: /bin/sh -c "crontab ./crontab && cron && service cron reload && php spark serve --host 0.0.0.0" - ports: - - 8080:8080 - volumes: - - .:/castopod-host - depends_on: - - redis - - mariadb - networks: - - castopod - - redis: - image: redis:alpine - container_name: castopod-host_redis - ports: - - 6379:6379 - volumes: - - redis:/data - networks: - - castopod - - mariadb: - image: mariadb:latest - container_name: castopod-host_mariadb - ports: - - 3306:3306 - volumes: - - mariadb:/var/lib/mysql - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: castopod - MYSQL_USER: podlibre - MYSQL_PASSWORD: castopod - networks: - - castopod - - phpmyadmin: - image: phpmyadmin/phpmyadmin:latest - container_name: castopod-host_phpmyadmin - environment: - PMA_HOST: mariadb - PMA_PORT: 3306 - ports: - - 8888:80 - volumes: - - phpmyadmin:/sessions - depends_on: - - mariadb - networks: - - castopod - -volumes: - redis: - mariadb: - phpmyadmin: diff --git a/docker/ci/Dockerfile b/docker/ci/Dockerfile new file mode 100644 index 00000000..bae95838 --- /dev/null +++ b/docker/ci/Dockerfile @@ -0,0 +1,40 @@ +#################################################### +# Castopod CI/CD docker file +#################################################### +# ⚠️ NOT optimized for production +# should be used only for continuous integration +#--------------------------------------------------- +FROM php:8.5-fpm-alpine3.23 + +LABEL maintainer="Yassine Doghri " + +RUN \ + # install composer + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer \ + # install ci requirements + && apk add --no-cache \ + nodejs \ + # install npm for @semantic-release/npm + npm \ + git \ + unzip \ + wget \ + jq \ + zip \ + openssh-client \ + rsync \ + icu-libs \ + mysql \ + mysql-client \ + && apk add --no-cache --virtual .php-ext-build-dep icu-dev \ + && docker-php-ext-install \ + intl \ + mysqli \ + && apk del .php-ext-build-dep \ + # install pnpm + && npm install --global corepack@latest \ + && corepack enable pnpm \ + # set pnpm store directory + && pnpm config set store-dir .pnpm-store \ + # set composer cache directory + && composer config -g cache-dir .composer-cache diff --git a/docker/production/.gitlab-ci.yml b/docker/production/.gitlab-ci.yml new file mode 100644 index 00000000..6256cc13 --- /dev/null +++ b/docker/production/.gitlab-ci.yml @@ -0,0 +1,112 @@ +stages: + - build + +docker-build-rolling: + stage: build + image: + name: docker.io/docker:29.2-dind + services: + - docker:29.2-dind + variables: + TAG: $CI_COMMIT_BRANCH + DOCKER_BUILDKIT: 1 + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + before_script: + # ensure the Docker config directory exists + - mkdir -p /root/.docker + # copy credentials to authenticate against registry + - cp ${DOCKER_HUB_CONFIG} /root/.docker/config.json + + - docker context create tls-environment + + # Create and use builder with optimized settings + - docker buildx create + --name fast-multiplatform + --driver docker-container + --driver-opt network=host + --driver-opt image=moby/buildkit:v0.27.1 + --use + tls-environment + + # initialize and boot fast-multiplatform builder + # configure BuildKit features that aren't enabled by default + - docker buildx inspect --bootstrap + script: + - docker buildx build + --target production + --secret id=maxmind-licence-key,env=MAXMIND_LICENCE_KEY + --platform linux/amd64 + --file docker/production/Dockerfile + --push + --tag ${DOCKER_IMAGE_CASTOPOD}:${TAG} + . + rules: + - if: $CI_COMMIT_BRANCH == 'develop' + +docker-build-release: + stage: build + image: + name: docker.io/docker:29.2-dind + services: + - docker:29.2-dind + variables: + DOCKER_BUILDKIT: 1 + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_CERTDIR: "/certs" + before_script: + # ensure the Docker config directory exists + - mkdir -p /root/.docker + # copy credentials to authenticate against registry + - cp ${DOCKER_HUB_CONFIG} /root/.docker/config.json + + ## Prepare Docker image tags from git tag + ## -------------------------------------- + # extract full SemVer from git tag (remove leading "v") + - export IMAGE_TAG_VERSION=$(echo "$CI_COMMIT_TAG" | sed 's/^v//') + # extract channel (prerelease like "alpha", "beta", "next"; "latest" for stable) + - export IMAGE_TAG_CHANNEL=$(echo "$IMAGE_TAG_VERSION" | sed 's/^[^-]*-\([^.]*\)\..*/\1/; t; s/.*/latest/') + # extract major version number (first SemVer component) + - export IMAGE_TAG_MAJOR=$(echo "$IMAGE_TAG_VERSION" | sed 's/\..*//') + # construct major-channel tag ("X" for stable, "X-channel" for prerelease) + - export IMAGE_TAG_MAJOR_CHANNEL=$([ "$IMAGE_TAG_CHANNEL" = "latest" ] && echo "$IMAGE_TAG_MAJOR" || echo "${IMAGE_TAG_MAJOR}-${IMAGE_TAG_CHANNEL}") + + - docker context create tls-environment + + # Create and use builder with optimized settings + - docker buildx create + --name fast-multiplatform + --driver docker-container + --driver-opt network=host + --driver-opt image=moby/buildkit:v0.27.1 + --use + tls-environment + + # initialize and boot fast-multiplatform builder + # configure BuildKit features that aren't enabled by default + - docker buildx inspect --bootstrap + script: + - docker buildx build + --target production + --secret id=maxmind-licence-key,env=MAXMIND_LICENCE_KEY + --platform linux/amd64 + --file docker/production/Dockerfile + --push + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_VERSION} + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_CHANNEL} + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_MAJOR_CHANNEL} + . + # when --platform=linux/amd64,linux/arm64: amd64 image takes too long to be pushed as it needs to wait for arm64 to be built + # --> build and push amd64 image first, then overwrite manifest after building arm64 + - docker buildx build + --target production + --secret id=maxmind-licence-key,env=MAXMIND_LICENCE_KEY + --platform linux/amd64,linux/arm64 + --file docker/production/Dockerfile + --push + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_VERSION} + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_CHANNEL} + --tag ${DOCKER_IMAGE_CASTOPOD}:${IMAGE_TAG_MAJOR_CHANNEL} + . + rules: + - if: $CI_COMMIT_TAG diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile new file mode 100644 index 00000000..f55d3cfc --- /dev/null +++ b/docker/production/Dockerfile @@ -0,0 +1,154 @@ +#################################################### +# Castopod's Production Dockerfile +#################################################### +# An optimized Dockerfile for production using +# multi-stage builds: +# 1. BUNDLE castopod +# 2. BUILD the FrankenPHP/debian based prod image +#--------------------------------------------------- + +ARG PHP_VERSION="8.5" + +#################################################### +# BUNDLE STAGE +# ------------------------------------------------- +# Bundle castopod for production using +# a PHP / Alpine image +#--------------------------------------------------- +FROM php:${PHP_VERSION}-alpine3.23 AS bundle + +LABEL maintainer="Yassine Doghri " + +COPY . /castopod-src +WORKDIR /castopod-src + +COPY --from=composer:2.9 /usr/bin/composer /usr/local/bin/composer + +RUN \ + # download GeoLite2-City archive and extract it to writable/uploads + --mount=type=secret,id=maxmind-licence-key,env=MAXMIND_LICENCE_KEY \ + wget -c "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=$MAXMIND_LICENCE_KEY&suffix=tar.gz" -O - | tar -xz -C ./writable/uploads/ \ + # rename extracted archives' folders + && mv ./writable/uploads/GeoLite2-City* ./writable/uploads/GeoLite2-City + +RUN \ + # install composer globally + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \ + # install node and pnpm + && apk add --no-cache \ + nodejs \ + pnpm \ + git \ + rsync \ + # install production dependencies only using the --no-dev option + && composer install --no-dev --prefer-dist --no-ansi --no-interaction --no-progress --ignore-platform-reqs \ + # install js dependencies based on lockfile + && pnpm install --frozen-lockfile \ + # build all production static assets (css, js, images, icons, fonts, etc.) + && pnpm run build \ + # create castopod folder bundle: uses .rsync-filter (-F) file to copy only needed files + && rsync -aF . /castopod + + +#################################################### +# BUILD STAGE +# ------------------------------------------------- +# Define production image based on FrankenPHP / +# Debian with services managed by s6-overlay +#--------------------------------------------------- +FROM serversideup/php:${PHP_VERSION}-frankenphp-trixie AS production + +LABEL maintainer="Yassine Doghri " + +USER root + +ARG TARGETARCH + +# Latest releases available at https://github.com/aptible/supercronic/releases +# add supercronic to handle cron jobs +RUN if [ "$TARGETARCH" = "amd64" ]; then \ + SUPERCRONIC_URL="https://github.com/aptible/supercronic/releases/download/v0.2.43/supercronic-linux-amd64"; \ + SUPERCRONIC_SHA1SUM="f97b92132b61a8f827c3faf67106dc0e4467ccf2"; \ + SUPERCRONIC="supercronic-linux-amd64"; \ + elif [ "$TARGETARCH" = "arm64" ]; then \ + SUPERCRONIC_URL="https://github.com/aptible/supercronic/releases/download/v0.2.43/supercronic-linux-arm64"; \ + SUPERCRONIC_SHA1SUM="5c6266786c2813d6f8a99965d84452faae42b483"; \ + SUPERCRONIC="supercronic-linux-arm64"; \ + else \ + echo "Unsupported TARGETARCH: $TARGETARCH"; exit 1; \ + fi && \ + curl -fsSLO "$SUPERCRONIC_URL" \ + && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ + && chmod +x "$SUPERCRONIC" \ + && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ + && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + +ARG S6_OVERLAY_VERSION=3.2.2.0 + +# add s6-overlay process manager +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp +RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz + +# add Arch-specific tarball +RUN if [ "$TARGETARCH" = "amd64" ]; then \ + S6_ARCH="x86_64"; \ + elif [ "$TARGETARCH" = "arm64" ]; then \ + S6_ARCH="aarch64"; \ + else \ + echo "Unsupported TARGETARCH: $TARGETARCH"; exit 1; \ + fi && \ + curl -fsSL -o /tmp/s6-overlay-${S6_ARCH}.tar.xz \ + "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" && \ + tar -C / -Jxpf /tmp/s6-overlay-${S6_ARCH}.tar.xz && \ + rm /tmp/s6-overlay-${S6_ARCH}.tar.xz + +# copy s6-overlay services +COPY --chown=www-data:www-data docker/production/s6-rc.d /etc/s6-overlay/s6-rc.d + +# make prepare-environment executable for bootstrapping the Castopod environment +RUN chmod +x /etc/s6-overlay/s6-rc.d/bootstrap/prepare-environment.sh + +RUN \ + apt-get update \ + && apt-get install -y \ + ffmpeg \ + libfreetype6-dev \ + libjpeg62-turbo-dev \ + libpng-dev \ + libwebp-dev \ + libicu-dev \ + && install-php-extensions \ + intl \ + mysqli \ + exif \ + gd \ + # As of PHP 7.4 we don't need to add --with-png + && docker-php-ext-configure gd --with-webp --with-jpeg --with-freetype + +# copy castopod bundle from bundle stage +COPY --from=bundle --chown=www-data:www-data /castopod /app + +RUN \ + chmod -R 550 /app/ \ + && chmod -R 770 /app/public/media/ \ + && chmod -R 770 /app/writable/ \ + && chmod 750 /app/ + +ARG \ + PHP_MEMORY_LIMIT=512M \ + PHP_MAX_EXECUTION_TIME=300 \ + PHP_UPLOAD_MAX_FILE_SIZE=512M \ + PHP_POST_MAX_SIZE=512M \ + PHP_OPCACHE_ENABLE=1 + +ENV \ + PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT} \ + PHP_MAX_EXECUTION_TIME=${PHP_MAX_EXECUTION_TIME} \ + PHP_UPLOAD_MAX_FILE_SIZE=${PHP_UPLOAD_MAX_FILE_SIZE} \ + PHP_POST_MAX_SIZE=${PHP_POST_MAX_SIZE} \ + PHP_OPCACHE_ENABLE=${PHP_OPCACHE_ENABLE} + +USER www-data + +ENTRYPOINT ["docker-php-serversideup-entrypoint"] +CMD ["/init"] diff --git a/app/Resources/types/js/main.d.ts b/docker/production/s6-rc.d/bootstrap/dependencies.d/frankenphp similarity index 100% rename from app/Resources/types/js/main.d.ts rename to docker/production/s6-rc.d/bootstrap/dependencies.d/frankenphp diff --git a/docker/production/s6-rc.d/bootstrap/prepare-environment.sh b/docker/production/s6-rc.d/bootstrap/prepare-environment.sh new file mode 100644 index 00000000..bb5a9a36 --- /dev/null +++ b/docker/production/s6-rc.d/bootstrap/prepare-environment.sh @@ -0,0 +1,277 @@ +#!/command/with-contenv sh + +ENV_FILE_LOCATION=/app/.env + +log_error() { + printf "\033[0;31mERROR:\033[0m $1\n" + exit 1 +} + +log_warning() { + printf "\033[0;33mWARNING:\033[0m $1\n" +} + +log_info() { + printf "\033[0;34mINFO:\033[0m $1\n" +} + +# Remove .env file if exists to recreate it. +rm -f $ENV_FILE_LOCATION + +if [ -z "${CP_BASEURL}" ] +then + log_error "CP_BASEURL must be set" +fi + +if [ -z "${CP_MEDIA_BASEURL}" ] +then + log_info "CP_MEDIA_BASEURL is empty, using CP_BASEURL by default" + CP_MEDIA_BASEURL=$CP_BASEURL +fi + +if [ -z "${CP_ADMIN_GATEWAY}" ] +then + log_info "CP_ADMIN_GATEWAY is empty, using default \"cp-admin\"" + CP_ADMIN_GATEWAY="cp-admin" +fi + +if [ -z "${CP_AUTH_GATEWAY}" ] +then + log_info "CP_AUTH_GATEWAY is empty, using default \"cp-auth\"" + CP_AUTH_GATEWAY="cp-auth" +fi + +if [ -z "${CP_ANALYTICS_SALT}" ] +then + log_error "CP_ANALYTICS_SALT is empty, this is mandatory, generate a new one with tr -dc \\!\\#-\\&\\(-\\[\\]-\\_a-\\~ $ENV_FILE_LOCATION +app.baseURL="${CP_BASEURL}" +media.baseURL="${CP_MEDIA_BASEURL}" +EOF + +if [ "${CP_DISABLE_HTTPS}" = "1" ] +then + log_warning "HTTPS redirection is disabled for testing purposes, please enable it in production mode" + echo "app.forceGlobalSecureRequests=false" >> $ENV_FILE_LOCATION +else + echo "HTTPS redirection is enabled by default (mandatory to federate with the fediverse), use CP_DISABLE_HTTPS=1 to disable it for testing purposes" +fi + +cat << EOF >> $ENV_FILE_LOCATION +admin.gateway="${CP_ADMIN_GATEWAY}" +auth.gateway="${CP_AUTH_GATEWAY}" + +analytics.salt="${CP_ANALYTICS_SALT}" + +database.default.hostname="${CP_DATABASE_HOSTNAME}" +database.default.database="${CP_DATABASE_NAME}" +database.default.username="${CP_DATABASE_USERNAME}" +database.default.password="${CP_DATABASE_PASSWORD}" +database.default.DBPrefix="${CP_DATABASE_PREFIX}" + +cache.handler="${CP_CACHE_HANDLER}" +EOF + +if [ "${CP_CACHE_HANDLER}" = "redis" ] +then + cat << EOF >> $ENV_FILE_LOCATION +cache.redis.host="${CP_REDIS_HOST}" +cache.redis.password=${CP_REDIS_PASSWORD} +cache.redis.port=${CP_REDIS_PORT} +cache.redis.database=${CP_REDIS_DATABASE} +EOF +fi + +if [ "${CP_ENABLE_2FA}" = "true" ] +then + cat << EOF >> $ENV_FILE_LOCATION +auth.enable2FA=true +EOF +fi + +if [ "${CP_MEDIA_FILE_MANAGER}" = "s3" ] +then + cat << EOF >> $ENV_FILE_LOCATION +media.fileManager=s3 +media.s3.endpoint=${CP_MEDIA_S3_ENDPOINT} +media.s3.key=${CP_MEDIA_S3_KEY} +media.s3.secret=${CP_MEDIA_S3_SECRET} +media.s3.region=${CP_MEDIA_S3_REGION} +media.s3.bucket=${CP_MEDIA_S3_BUCKET} +EOF +fi + +if [ ! -z "${CP_MEDIA_S3_PROTOCOL}" ] +then + cat << EOF >> $ENV_FILE_LOCATION +media.s3.protocol=${CP_MEDIA_S3_PROTOCOL} +EOF +fi + +if [ ! -z "${CP_MEDIA_S3_PATH_STYLE_ENDPOINT}" ] +then + cat << EOF >> $ENV_FILE_LOCATION +media.s3.pathStyleEndpoint=${CP_MEDIA_S3_PATH_STYLE_ENDPOINT} +EOF +fi + +if [ ! -z "${CP_MEDIA_S3_KEY_PREFIX}" ] +then + cat << EOF >> $ENV_FILE_LOCATION +media.s3.keyPrefix=${CP_MEDIA_S3_KEY_PREFIX} +EOF +fi + +if [ ! -z "${CP_EMAIL_SMTP_HOST}" ] +then + if [ -z "${CP_EMAIL_SMTP_USERNAME}" ] + then + log_error "When CP_EMAIL_SMTP_HOST is provided, CP_EMAIL_SMTP_USERNAME must be set" + fi + + if [ -z "${CP_EMAIL_SMTP_PASSWORD}" ] + then + log_error "When CP_EMAIL_SMTP_HOST is provided, CP_EMAIL_SMTP_PASSWORD must be set" + fi + + if [ -z "${CP_EMAIL_FROM}" ] + then + log_error "When CP_EMAIL_SMTP_HOST is provided, CP_EMAIL_FROM must be set" + fi + + cat << EOF >> $ENV_FILE_LOCATION +email.protocol="smtp" +email.SMTPHost="${CP_EMAIL_SMTP_HOST}" +email.SMTPUser=${CP_EMAIL_SMTP_USERNAME} +email.SMTPPass=${CP_EMAIL_SMTP_PASSWORD} +email.fromEmail=${CP_EMAIL_FROM} +EOF + + if [ ! -z "${CP_EMAIL_SMTP_PORT}" ] + then + cat << EOF >> $ENV_FILE_LOCATION +email.SMTPPort=${CP_EMAIL_SMTP_PORT} +EOF + fi + + if [ ! -z "${CP_EMAIL_SMTP_CRYPTO}" ] + then + if [ "${CP_EMAIL_SMTP_CRYPTO}" != "ssl" ] && [ "${CP_EMAIL_SMTP_CRYPTO}" != "tls" ] + then + log_error "CP_EMAIL_SMTP_CRYPTO must be ssl or tls" + fi + cat << EOF >> $ENV_FILE_LOCATION +email.SMTPCrypto=${CP_EMAIL_SMTP_CRYPTO} +EOF + fi +fi + +log_info "Using config:" +cat $ENV_FILE_LOCATION + +# prevent .env from being writable +chmod -w $ENV_FILE_LOCATION + +#Run database migrations +/usr/local/bin/php /var/www/html/spark castopod:database-update + +# clear cache to account for new assets and any change in data structure +/usr/local/bin/php /var/www/html/spark cache:clear diff --git a/docker/production/s6-rc.d/bootstrap/type b/docker/production/s6-rc.d/bootstrap/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/docker/production/s6-rc.d/bootstrap/type @@ -0,0 +1 @@ +oneshot diff --git a/docker/production/s6-rc.d/bootstrap/up b/docker/production/s6-rc.d/bootstrap/up new file mode 100644 index 00000000..4abab1a4 --- /dev/null +++ b/docker/production/s6-rc.d/bootstrap/up @@ -0,0 +1,2 @@ +#!/command/with-contenv sh +/etc/s6-overlay/s6-rc.d/bootstrap/prepare-environment.sh diff --git a/docker/production/s6-rc.d/frankenphp/dependencies.d/base b/docker/production/s6-rc.d/frankenphp/dependencies.d/base new file mode 100644 index 00000000..e69de29b diff --git a/docker/production/s6-rc.d/frankenphp/run b/docker/production/s6-rc.d/frankenphp/run new file mode 100644 index 00000000..1193fcc3 --- /dev/null +++ b/docker/production/s6-rc.d/frankenphp/run @@ -0,0 +1,2 @@ +#!/command/with-contenv sh +frankenphp run --config /etc/frankenphp/Caddyfile --adapter caddyfile diff --git a/docker/production/s6-rc.d/frankenphp/type b/docker/production/s6-rc.d/frankenphp/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/docker/production/s6-rc.d/frankenphp/type @@ -0,0 +1 @@ +longrun diff --git a/docker/production/s6-rc.d/supercronic/crontab b/docker/production/s6-rc.d/supercronic/crontab new file mode 100644 index 00000000..8382f92f --- /dev/null +++ b/docker/production/s6-rc.d/supercronic/crontab @@ -0,0 +1 @@ +* * * * * /usr/local/bin/php /var/www/html/spark tasks:run >> /dev/null 2>&1 diff --git a/docker/production/s6-rc.d/supercronic/dependencies.d/frankenphp b/docker/production/s6-rc.d/supercronic/dependencies.d/frankenphp new file mode 100644 index 00000000..e69de29b diff --git a/docker/production/s6-rc.d/supercronic/run b/docker/production/s6-rc.d/supercronic/run new file mode 100644 index 00000000..73b9b0cf --- /dev/null +++ b/docker/production/s6-rc.d/supercronic/run @@ -0,0 +1,2 @@ +#!/command/with-contenv sh +supercronic /etc/s6-overlay/s6-rc.d/supercronic/crontab diff --git a/docker/production/s6-rc.d/supercronic/type b/docker/production/s6-rc.d/supercronic/type new file mode 100644 index 00000000..5883cff0 --- /dev/null +++ b/docker/production/s6-rc.d/supercronic/type @@ -0,0 +1 @@ +longrun diff --git a/docker/production/s6-rc.d/user/contents.d/bootstrap b/docker/production/s6-rc.d/user/contents.d/bootstrap new file mode 100644 index 00000000..e69de29b diff --git a/docker/production/s6-rc.d/user/contents.d/frankenphp b/docker/production/s6-rc.d/user/contents.d/frankenphp new file mode 100644 index 00000000..e69de29b diff --git a/docker/production/s6-rc.d/user/contents.d/supercronic b/docker/production/s6-rc.d/user/contents.d/supercronic new file mode 100644 index 00000000..e69de29b diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..6240da8b --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,21 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/docs/.gitlab-ci.yml b/docs/.gitlab-ci.yml new file mode 100644 index 00000000..d0f1bde5 --- /dev/null +++ b/docs/.gitlab-ci.yml @@ -0,0 +1,76 @@ +image: node:22 + +stages: + - build + - deploy + +.documentation-setup: + before_script: + - npm install --global corepack@latest + - corepack enable + - corepack prepare pnpm@latest-10 --activate + - pnpm config set store-dir .pnpm-store + - cd docs + - chmod +x ./scripts/i18n-filter.sh + - ./scripts/i18n-filter.sh src/content/docs + - pnpm install + +cache: + key: + files: + - docs/pnpm-lock.yaml + paths: + - .pnpm-store + +# This job only serves for validating that the docs builds correctly on all non deployment branches +build: + extends: .documentation-setup + stage: build + script: + - pnpm run build + rules: + - if: $CI_COMMIT_BRANCH =~ /^(develop|main|alpha|beta|next)$/ + when: never + - when: on_success + +build-production: + extends: .documentation-setup + stage: build + environment: + name: production + url: https://docs.castopod.org/ + script: + - BASE=/$CI_COMMIT_REF_SLUG pnpm run build --outDir=./dist/$CI_COMMIT_REF_SLUG --base=/$CI_COMMIT_REF_SLUG + artifacts: + paths: + - docs/dist/$CI_COMMIT_REF_SLUG + expire_in: 30 mins + rules: + - if: $CI_COMMIT_BRANCH =~ /^(develop|main|alpha|beta|next)$/ + +deploy: + stage: deploy + environment: + name: production + url: https://docs.castopod.org/ + variables: + HOST: $DOCS_HOST + USER: $DOCS_USER + TEMP_DIRECTORY: $DOCS_TEMP_DIRECTORY/$CI_COMMIT_REF_SLUG/ + DIRECTORY: $DOCS_DIRECTORY/$CI_COMMIT_REF_SLUG/ + SSH_PORT: 3242 + SOURCE_FOLDER: "docs/dist/$CI_COMMIT_REF_SLUG/" + before_script: + # install rsync for file transfers + - apt-get update && apt-get install rsync -y + # Run ssh-agent (inside the build environment) + - eval $(ssh-agent -s) + # Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store + - ssh-add <(echo "$SSH_PRIVATE_KEY" | base64 --decode) + - mkdir -p ~/.ssh + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' + script: + - rsync -avzuh -e "ssh -p $SSH_PORT" $SOURCE_FOLDER $USER@$HOST:$TEMP_DIRECTORY --progress + - ssh $USER@$HOST -p $SSH_PORT "rsync -rtv $TEMP_DIRECTORY $DIRECTORY" + rules: + - if: $CI_COMMIT_BRANCH =~ /^(develop|main|alpha|beta|next)$/ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..34351f25 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,54 @@ +# Castopod Docs + +[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build) + +```sh +pnpm create astro@latest -- --template starlight +``` + +> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! + +## 🚀 Project Structure + +Inside of your Astro + Starlight project, you'll see the following folders and +files: + +```sh +. +├── public/ +├── src/ +│ ├── assets/ +│ ├── content/ +│ │ └── docs/ +│ └── content.config.ts +├── astro.config.mjs +├── package.json +└── tsconfig.json +``` + +Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. +Each file is exposed as a route based on its file name. + +Images can be added to `src/assets/` and embedded in Markdown with a relative +link. + +Static assets, like favicons, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :--------------------- | :----------------------------------------------- | +| `pnpm install` | Installs dependencies | +| `pnpm dev` | Starts local dev server at `localhost:4321` | +| `pnpm build` | Build your production site to `./dist/` | +| `pnpm preview` | Preview your build locally, before deploying | +| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` | +| `pnpm astro -- --help` | Get help using the Astro CLI | + +## 👀 Want to learn more? + +Check out [Starlight’s docs](https://starlight.astro.build/), read +[the Astro documentation](https://docs.astro.build), or jump into the +[Astro Discord server](https://astro.build/chat). diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 00000000..d641ec7f --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,413 @@ +// @ts-check +import { defineConfig } from "astro/config"; +import starlight from "@astrojs/starlight"; +import starlightOpenAPI from "starlight-openapi"; + +const site = "https://docs.castopod.org/"; +const base = process.env.BASE ?? "/docs"; + +// https://astro.build/config +export default defineConfig({ + server: { + host: true, + }, + site, + base, + integrations: [ + starlight({ + title: "Castopod Docs", + description: + "Check out the Castopod documentation! Install your own free & open-source podcast host, help make it better by contributing, or simply learn more about Castopod!", + components: { + ThemeSelect: "./src/components/ThemeSelect.astro", + }, + logo: { + src: "./src/assets/castopod-logo-inline.svg", + replacesTitle: true, + }, + favicon: "/favicon.ico", + customCss: [ + "@fontsource/inter/400.css", + "@fontsource/inter/600.css", + "@fontsource/rubik/700.css", + "./src/styles/custom.css", + ], + head: [ + { + tag: "meta", + attrs: { + property: "og:type", + content: "website", + }, + }, + { + tag: "meta", + attrs: { + property: "og:image", + content: base + "/open-graph.jpg?v=1", + }, + }, + { + tag: "meta", + attrs: { property: "og:image:type", content: "image/jpeg" }, + }, + { tag: "meta", attrs: { property: "og:image:width", content: "1200" } }, + { tag: "meta", attrs: { property: "og:image:height", content: "630" } }, + { + tag: "meta", + attrs: { + property: "og:image:alt", + content: + "Castopod mascot waving hello and holding a browser showcasing the Castopod documentation.", + }, + }, + { + tag: "meta", + attrs: { property: "og:url", content: "https://docs.castopod.org/" }, + }, + { tag: "meta", attrs: { name: "twitter:site", content: "@castopod" } }, + { + tag: "meta", + attrs: { name: "twitter:card", content: "summary_large_image" }, + }, + { + tag: "meta", + attrs: { name: "twitter:creator", content: "@ad_aures" }, + }, + { + tag: "script", + attrs: { + src: "https://analytics.castopod.org/js/plausible.js", + "data-domain": "docs.castopod.org", + defer: true, + }, + }, + ], + social: [ + { + icon: "discord", + label: "Discord", + href: "https://castopod.org/chat", + }, + { + icon: "blueSky", + label: "Bluesky", + href: "https://bsky.app/profile/castopod.org", + }, + { + icon: "mastodon", + label: "Mastodon", + href: "https://podlibre.social/@Castopod", + }, + { + icon: "gitlab", + label: "Source code", + href: "https://code.castopod.org/adaures/castopod", + }, + { + icon: "github", + label: "Github", + href: "https://github.com/ad-aures/castopod", + }, + ], + defaultLocale: "en", + locales: { + en: { + label: "English", + }, + ca: { + label: "Català", + }, + de: { + label: "Deutsch", + }, + es: { + label: "Español", + }, + fr: { + label: "Français", + }, + "nn-no": { + label: "Norsk nynorsk", + lang: "nn-NO", + }, + "pt-br": { + label: "Português do Brasil", + lang: "pt-BR", + }, + "sr-latn": { + label: "Srpski", + lang: "sr-Latn", + }, + "zh-hans": { + label: "中文", + lang: "zh-Hans", + }, + }, + plugins: [ + // Generate the OpenAPI documentation pages. + starlightOpenAPI([ + { + base: "en/api", + label: "API reference", + schema: "../modules/Api/Rest/V1/schema.yaml", + collapsed: true, + }, + ]), + ], + sidebar: [ + { + label: "Introduction", + link: "/", + translations: { + fr: "Installer", + "pt-br": "Instalar", + "nn-no": "Installer", + }, + }, + { + label: "Getting started", + translations: { + fr: "Commencer", + "pt-br": "Começando", + "nn-no": "Starter", + }, + items: [ + // Each item here is one entry in the navigation menu. + { + label: "Install", + link: "/getting-started/install/", + translations: { + fr: "Installer", + "pt-br": "Instalar", + "nn-no": "Installer", + }, + }, + { + label: "Docker", + link: "/getting-started/docker/", + }, + { + label: "Security", + link: "/getting-started/security/", + translations: { + fr: "Sécurité", + "pt-br": "Segurança", + "nn-no": "Sikkerhet", + }, + }, + { + label: "Update", + link: "/getting-started/update/", + translations: { + fr: "Mise à jour", + "pt-br": "Atualizar", + "nn-no": "Oppdaterer", + }, + }, + { + label: "Auth", + link: "/getting-started/auth/", + translations: { + fr: "Authentification", + "pt-br": "Autenticação", + "nn-no": "Autentisering", + }, + }, + { + label: "Create your first podcast", + link: "/getting-started/create-podcast/", + translations: {}, + }, + { + label: "Create your first episode", + link: "/getting-started/create-episode/", + translations: {}, + }, + ], + }, + { + label: "Plugins", + items: [ + { + label: "Introduction", + link: "/plugins/", + }, + { + label: "Install plugins", + link: "/plugins/install", + }, + { + label: "Create a plugin", + link: "/plugins/create", + }, + { + label: "Share your plugin", + link: "/plugins/share", + }, + { + label: "Reference", + items: [ + { + label: "plugins.json", + link: "/plugins/reference/plugins-json", + }, + { + label: "plugins-lock.json", + link: "/plugins/reference/plugins-lock-json", + }, + { + label: "manifest.json", + link: "/plugins/reference/manifest", + }, + { + label: "hooks", + link: "/plugins/reference/hooks", + }, + ], + }, + ], + }, + // TODO: openapi plugin does not handle i18n, manual sidebar workaround + // Add the generated sidebar group to the sidebar. + // ...openAPISidebarGroups, + { + label: "API reference", + translations: {}, + items: [ + { + label: "Overview", + link: "/api", + }, + { + label: "Operations", + items: [ + { + label: "Get all podcasts", + link: "/api/operations/get-all-podcasts", + }, + { + label: "Get podcast by ID", + link: "/api/operations/get-podcast-by-id", + }, + { + label: "Get all episodes", + link: "/api/operations/get-all-episodes", + }, + { + label: "Add a new episode", + link: "/api/operations/add-episode", + }, + { + label: "Get episode by ID", + link: "/api/operations/get-episode-by-id", + }, + { + label: "Publish an episode", + link: "/api/operations/publish-episode", + }, + ], + }, + ], + }, + { + label: "User guide", + translations: {}, + items: [ + { + label: "Introduction", + link: "/user-guide/", + }, + { + label: "Manage your instance", + translations: {}, + collapsed: true, + items: [ + { + label: "Introduction", + link: "/user-guide/instance/", + }, + { + label: "Add a podcast", + link: "/user-guide/instance/podcast", + translations: {}, + }, + { + label: "Persons", + link: "/user-guide/instance/persons", + translations: {}, + }, + + { + label: "Fediverse", + link: "/user-guide/instance/fediverse", + translations: {}, + }, + { + label: "Users", + link: "/user-guide/instance/users", + translations: {}, + }, + { + label: "Pages", + link: "/user-guide/instance/pages", + translations: {}, + }, + { + label: "Settings", + link: "/user-guide/instance/settings", + translations: {}, + }, + ], + }, + { + label: "Manage your podcasts", + translations: {}, + collapsed: true, + items: [ + { + label: "Introduction", + link: "/user-guide/podcast/", + }, + { + label: "Podcast dashboard", + link: "/user-guide/podcast/dashboard", + translations: {}, + }, + { + label: "Episodes", + link: "/user-guide/podcast/episodes", + translations: {}, + }, + + { + label: "Analytics", + link: "/user-guide/podcast/analytics", + translations: {}, + }, + { + label: "Broadcasting", + link: "/user-guide/podcast/broadcast", + translations: {}, + }, + { + label: "Contributors", + link: "/user-guide/podcast/contributors", + translations: {}, + }, + ], + }, + { + label: "Website overview", + link: "/user-guide/website/", + translations: {}, + }, + ], + }, + ], + editLink: { + baseUrl: "https://code.castopod.org/adaures/castopod/-/edit/main/docs/", + }, + }), + ], +}); diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000..9258fab6 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,21 @@ +{ + "name": "castopod-docs", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro", + "prepare": "astro telemetry disable" + }, + "dependencies": { + "@astrojs/starlight": "^0.37.6", + "@fontsource/inter": "^5.2.8", + "@fontsource/rubik": "^5.2.8", + "astro": "^5.17.2", + "sharp": "^0.34.5", + "starlight-openapi": "^0.22.0" + } +} diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml new file mode 100644 index 00000000..45dac61d --- /dev/null +++ b/docs/pnpm-lock.yaml @@ -0,0 +1,6029 @@ +lockfileVersion: "9.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + "@astrojs/starlight": + specifier: ^0.37.6 + version: 0.37.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)) + "@fontsource/inter": + specifier: ^5.2.8 + version: 5.2.8 + "@fontsource/rubik": + specifier: ^5.2.8 + version: 5.2.8 + astro: + specifier: ^5.17.2 + version: 5.17.2(rollup@4.57.1)(typescript@5.9.3) + sharp: + specifier: ^0.34.5 + version: 0.34.5 + starlight-openapi: + specifier: ^0.22.0 + version: 0.22.0(@astrojs/markdown-remark@6.3.10)(@astrojs/starlight@0.37.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)))(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3))(openapi-types@12.1.3) + +packages: + "@apidevtools/json-schema-ref-parser@13.0.5": + resolution: + { + integrity: sha512-xfh4xVJD62gG6spIc7lwxoWT+l16nZu1ELyU8FkjaP/oD2yP09EvLAU6KhtudN9aML2Khhs9pY6Slr7KGTES3w==, + } + engines: { node: ">= 16" } + + "@astrojs/compiler@2.13.1": + resolution: + { + integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==, + } + + "@astrojs/internal-helpers@0.7.5": + resolution: + { + integrity: sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==, + } + + "@astrojs/markdown-remark@6.3.10": + resolution: + { + integrity: sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==, + } + + "@astrojs/mdx@4.3.13": + resolution: + { + integrity: sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==, + } + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } + peerDependencies: + astro: ^5.0.0 + + "@astrojs/prism@3.3.0": + resolution: + { + integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==, + } + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } + + "@astrojs/sitemap@3.7.0": + resolution: + { + integrity: sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==, + } + + "@astrojs/starlight@0.37.6": + resolution: + { + integrity: sha512-wQrKwH431q+8FsLBnNQeG+R36TMtEGxTQ2AuiVpcx9APcazvL3n7wVW8mMmYyxX0POjTnxlcWPkdMGR3Yj1L+w==, + } + peerDependencies: + astro: ^5.5.0 + + "@astrojs/telemetry@3.3.0": + resolution: + { + integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==, + } + engines: { node: 18.20.8 || ^20.3.0 || >=22.0.0 } + + "@babel/code-frame@7.29.0": + resolution: + { + integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-string-parser@7.27.1": + resolution: + { + integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-identifier@7.28.5": + resolution: + { + integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, + } + engines: { node: ">=6.9.0" } + + "@babel/parser@7.29.0": + resolution: + { + integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + "@babel/runtime@7.28.6": + resolution: + { + integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==, + } + engines: { node: ">=6.9.0" } + + "@babel/types@7.29.0": + resolution: + { + integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==, + } + engines: { node: ">=6.9.0" } + + "@capsizecss/unpack@4.0.0": + resolution: + { + integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==, + } + engines: { node: ">=18" } + + "@ctrl/tinycolor@4.2.0": + resolution: + { + integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==, + } + engines: { node: ">=14" } + + "@emnapi/runtime@1.8.1": + resolution: + { + integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==, + } + + "@esbuild/aix-ppc64@0.25.12": + resolution: + { + integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [aix] + + "@esbuild/aix-ppc64@0.27.3": + resolution: + { + integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [aix] + + "@esbuild/android-arm64@0.25.12": + resolution: + { + integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [android] + + "@esbuild/android-arm64@0.27.3": + resolution: + { + integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [android] + + "@esbuild/android-arm@0.25.12": + resolution: + { + integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [android] + + "@esbuild/android-arm@0.27.3": + resolution: + { + integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [android] + + "@esbuild/android-x64@0.25.12": + resolution: + { + integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [android] + + "@esbuild/android-x64@0.27.3": + resolution: + { + integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [android] + + "@esbuild/darwin-arm64@0.25.12": + resolution: + { + integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [darwin] + + "@esbuild/darwin-arm64@0.27.3": + resolution: + { + integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [darwin] + + "@esbuild/darwin-x64@0.25.12": + resolution: + { + integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [darwin] + + "@esbuild/darwin-x64@0.27.3": + resolution: + { + integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [darwin] + + "@esbuild/freebsd-arm64@0.25.12": + resolution: + { + integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [freebsd] + + "@esbuild/freebsd-arm64@0.27.3": + resolution: + { + integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [freebsd] + + "@esbuild/freebsd-x64@0.25.12": + resolution: + { + integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [freebsd] + + "@esbuild/freebsd-x64@0.27.3": + resolution: + { + integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [freebsd] + + "@esbuild/linux-arm64@0.25.12": + resolution: + { + integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [linux] + + "@esbuild/linux-arm64@0.27.3": + resolution: + { + integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [linux] + + "@esbuild/linux-arm@0.25.12": + resolution: + { + integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [linux] + + "@esbuild/linux-arm@0.27.3": + resolution: + { + integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [linux] + + "@esbuild/linux-ia32@0.25.12": + resolution: + { + integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [linux] + + "@esbuild/linux-ia32@0.27.3": + resolution: + { + integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [linux] + + "@esbuild/linux-loong64@0.25.12": + resolution: + { + integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==, + } + engines: { node: ">=18" } + cpu: [loong64] + os: [linux] + + "@esbuild/linux-loong64@0.27.3": + resolution: + { + integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==, + } + engines: { node: ">=18" } + cpu: [loong64] + os: [linux] + + "@esbuild/linux-mips64el@0.25.12": + resolution: + { + integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==, + } + engines: { node: ">=18" } + cpu: [mips64el] + os: [linux] + + "@esbuild/linux-mips64el@0.27.3": + resolution: + { + integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==, + } + engines: { node: ">=18" } + cpu: [mips64el] + os: [linux] + + "@esbuild/linux-ppc64@0.25.12": + resolution: + { + integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [linux] + + "@esbuild/linux-ppc64@0.27.3": + resolution: + { + integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [linux] + + "@esbuild/linux-riscv64@0.25.12": + resolution: + { + integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==, + } + engines: { node: ">=18" } + cpu: [riscv64] + os: [linux] + + "@esbuild/linux-riscv64@0.27.3": + resolution: + { + integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==, + } + engines: { node: ">=18" } + cpu: [riscv64] + os: [linux] + + "@esbuild/linux-s390x@0.25.12": + resolution: + { + integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==, + } + engines: { node: ">=18" } + cpu: [s390x] + os: [linux] + + "@esbuild/linux-s390x@0.27.3": + resolution: + { + integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==, + } + engines: { node: ">=18" } + cpu: [s390x] + os: [linux] + + "@esbuild/linux-x64@0.25.12": + resolution: + { + integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [linux] + + "@esbuild/linux-x64@0.27.3": + resolution: + { + integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [linux] + + "@esbuild/netbsd-arm64@0.25.12": + resolution: + { + integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [netbsd] + + "@esbuild/netbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [netbsd] + + "@esbuild/netbsd-x64@0.25.12": + resolution: + { + integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [netbsd] + + "@esbuild/netbsd-x64@0.27.3": + resolution: + { + integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [netbsd] + + "@esbuild/openbsd-arm64@0.25.12": + resolution: + { + integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openbsd] + + "@esbuild/openbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openbsd] + + "@esbuild/openbsd-x64@0.25.12": + resolution: + { + integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [openbsd] + + "@esbuild/openbsd-x64@0.27.3": + resolution: + { + integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [openbsd] + + "@esbuild/openharmony-arm64@0.25.12": + resolution: + { + integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openharmony] + + "@esbuild/openharmony-arm64@0.27.3": + resolution: + { + integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openharmony] + + "@esbuild/sunos-x64@0.25.12": + resolution: + { + integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [sunos] + + "@esbuild/sunos-x64@0.27.3": + resolution: + { + integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [sunos] + + "@esbuild/win32-arm64@0.25.12": + resolution: + { + integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [win32] + + "@esbuild/win32-arm64@0.27.3": + resolution: + { + integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [win32] + + "@esbuild/win32-ia32@0.25.12": + resolution: + { + integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [win32] + + "@esbuild/win32-ia32@0.27.3": + resolution: + { + integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [win32] + + "@esbuild/win32-x64@0.25.12": + resolution: + { + integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [win32] + + "@esbuild/win32-x64@0.27.3": + resolution: + { + integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [win32] + + "@expressive-code/core@0.41.6": + resolution: + { + integrity: sha512-FvJQP+hG0jWi/FLBSmvHInDqWR7jNANp9PUDjdMqSshHb0y7sxx3vHuoOr6SgXjWw+MGLqorZyPQ0aAlHEok6g==, + } + + "@expressive-code/plugin-frames@0.41.6": + resolution: + { + integrity: sha512-d+hkSYXIQot6fmYnOmWAM+7TNWRv/dhfjMsNq+mIZz8Tb4mPHOcgcfZeEM5dV9TDL0ioQNvtcqQNuzA1sRPjxg==, + } + + "@expressive-code/plugin-shiki@0.41.6": + resolution: + { + integrity: sha512-Y6zmKBmsIUtWTzdefqlzm/h9Zz0Rc4gNdt2GTIH7fhHH2I9+lDYCa27BDwuBhjqcos6uK81Aca9dLUC4wzN+ng==, + } + + "@expressive-code/plugin-text-markers@0.41.6": + resolution: + { + integrity: sha512-PBFa1wGyYzRExMDzBmAWC6/kdfG1oLn4pLpBeTfIRrALPjcGA/59HP3e7q9J0Smk4pC7U+lWkA2LHR8FYV8U7Q==, + } + + "@fontsource/inter@5.2.8": + resolution: + { + integrity: sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==, + } + + "@fontsource/rubik@5.2.8": + resolution: + { + integrity: sha512-PIc8QR7FqWPcYhbdRiGff56vQlKqg/ytES1YqecSq1GkgxiH4TBshrFvDEOZ9JonUF9m1qQ+qXxJj7wD5zgXEw==, + } + + "@humanwhocodes/momoa@2.0.4": + resolution: + { + integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==, + } + engines: { node: ">=10.10.0" } + + "@img/colour@1.0.0": + resolution: + { + integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==, + } + engines: { node: ">=18" } + + "@img/sharp-darwin-arm64@0.34.5": + resolution: + { + integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [darwin] + + "@img/sharp-darwin-x64@0.34.5": + resolution: + { + integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-darwin-arm64@1.2.4": + resolution: + { + integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, + } + cpu: [arm64] + os: [darwin] + + "@img/sharp-libvips-darwin-x64@1.2.4": + resolution: + { + integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, + } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-linux-arm64@1.2.4": + resolution: + { + integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-arm@1.2.4": + resolution: + { + integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-ppc64@1.2.4": + resolution: + { + integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-riscv64@1.2.4": + resolution: + { + integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-s390x@1.2.4": + resolution: + { + integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-x64@1.2.4": + resolution: + { + integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linuxmusl-arm64@1.2.4": + resolution: + { + integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-libvips-linuxmusl-x64@1.2.4": + resolution: + { + integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-linux-arm64@0.34.5": + resolution: + { + integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-arm@0.34.5": + resolution: + { + integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-ppc64@0.34.5": + resolution: + { + integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-riscv64@0.34.5": + resolution: + { + integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-s390x@0.34.5": + resolution: + { + integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-x64@0.34.5": + resolution: + { + integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-linuxmusl-arm64@0.34.5": + resolution: + { + integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-linuxmusl-x64@0.34.5": + resolution: + { + integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-wasm32@0.34.5": + resolution: + { + integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [wasm32] + + "@img/sharp-win32-arm64@0.34.5": + resolution: + { + integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [win32] + + "@img/sharp-win32-ia32@0.34.5": + resolution: + { + integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ia32] + os: [win32] + + "@img/sharp-win32-x64@0.34.5": + resolution: + { + integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [win32] + + "@jridgewell/sourcemap-codec@1.5.5": + resolution: + { + integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, + } + + "@mdx-js/mdx@3.1.1": + resolution: + { + integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==, + } + + "@oslojs/encoding@1.1.0": + resolution: + { + integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==, + } + + "@pagefind/darwin-arm64@1.4.0": + resolution: + { + integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==, + } + cpu: [arm64] + os: [darwin] + + "@pagefind/darwin-x64@1.4.0": + resolution: + { + integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==, + } + cpu: [x64] + os: [darwin] + + "@pagefind/default-ui@1.4.0": + resolution: + { + integrity: sha512-wie82VWn3cnGEdIjh4YwNESyS1G6vRHwL6cNjy9CFgNnWW/PGRjsLq300xjVH5sfPFK3iK36UxvIBymtQIEiSQ==, + } + + "@pagefind/freebsd-x64@1.4.0": + resolution: + { + integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==, + } + cpu: [x64] + os: [freebsd] + + "@pagefind/linux-arm64@1.4.0": + resolution: + { + integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==, + } + cpu: [arm64] + os: [linux] + + "@pagefind/linux-x64@1.4.0": + resolution: + { + integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==, + } + cpu: [x64] + os: [linux] + + "@pagefind/windows-x64@1.4.0": + resolution: + { + integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==, + } + cpu: [x64] + os: [win32] + + "@readme/better-ajv-errors@2.4.0": + resolution: + { + integrity: sha512-9WODaOAKSl/mU+MYNZ2aHCrkoRSvmQ+1YkLj589OEqqjOAhbn8j7Z+ilYoiTu/he6X63/clsxxAB4qny9/dDzg==, + } + engines: { node: ">=18" } + peerDependencies: + ajv: 4.11.8 - 8 + + "@readme/openapi-parser@4.1.2": + resolution: + { + integrity: sha512-lAFH88r/CHs5VZDUocEda0OSMSQsr6801sziIjOKyVA+0hSFN+BPuelPF5XvkMROHecnPd+XEJN1iNQqCgER/g==, + } + engines: { node: ">=20" } + peerDependencies: + openapi-types: ">=7" + + "@readme/openapi-schemas@3.1.0": + resolution: + { + integrity: sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==, + } + engines: { node: ">=18" } + + "@rollup/pluginutils@5.3.0": + resolution: + { + integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + "@rollup/rollup-android-arm-eabi@4.57.1": + resolution: + { + integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==, + } + cpu: [arm] + os: [android] + + "@rollup/rollup-android-arm64@4.57.1": + resolution: + { + integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==, + } + cpu: [arm64] + os: [android] + + "@rollup/rollup-darwin-arm64@4.57.1": + resolution: + { + integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==, + } + cpu: [arm64] + os: [darwin] + + "@rollup/rollup-darwin-x64@4.57.1": + resolution: + { + integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==, + } + cpu: [x64] + os: [darwin] + + "@rollup/rollup-freebsd-arm64@4.57.1": + resolution: + { + integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==, + } + cpu: [arm64] + os: [freebsd] + + "@rollup/rollup-freebsd-x64@4.57.1": + resolution: + { + integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==, + } + cpu: [x64] + os: [freebsd] + + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": + resolution: + { + integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-arm-musleabihf@4.57.1": + resolution: + { + integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==, + } + cpu: [arm] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-arm64-gnu@4.57.1": + resolution: + { + integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-arm64-musl@4.57.1": + resolution: + { + integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-loong64-gnu@4.57.1": + resolution: + { + integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==, + } + cpu: [loong64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-loong64-musl@4.57.1": + resolution: + { + integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==, + } + cpu: [loong64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-ppc64-gnu@4.57.1": + resolution: + { + integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-ppc64-musl@4.57.1": + resolution: + { + integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==, + } + cpu: [ppc64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-riscv64-gnu@4.57.1": + resolution: + { + integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-riscv64-musl@4.57.1": + resolution: + { + integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==, + } + cpu: [riscv64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-s390x-gnu@4.57.1": + resolution: + { + integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-x64-gnu@4.57.1": + resolution: + { + integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-x64-musl@4.57.1": + resolution: + { + integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@rollup/rollup-openbsd-x64@4.57.1": + resolution: + { + integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==, + } + cpu: [x64] + os: [openbsd] + + "@rollup/rollup-openharmony-arm64@4.57.1": + resolution: + { + integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==, + } + cpu: [arm64] + os: [openharmony] + + "@rollup/rollup-win32-arm64-msvc@4.57.1": + resolution: + { + integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==, + } + cpu: [arm64] + os: [win32] + + "@rollup/rollup-win32-ia32-msvc@4.57.1": + resolution: + { + integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==, + } + cpu: [ia32] + os: [win32] + + "@rollup/rollup-win32-x64-gnu@4.57.1": + resolution: + { + integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==, + } + cpu: [x64] + os: [win32] + + "@rollup/rollup-win32-x64-msvc@4.57.1": + resolution: + { + integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==, + } + cpu: [x64] + os: [win32] + + "@shikijs/core@3.22.0": + resolution: + { + integrity: sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==, + } + + "@shikijs/engine-javascript@3.22.0": + resolution: + { + integrity: sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==, + } + + "@shikijs/engine-oniguruma@3.22.0": + resolution: + { + integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==, + } + + "@shikijs/langs@3.22.0": + resolution: + { + integrity: sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==, + } + + "@shikijs/themes@3.22.0": + resolution: + { + integrity: sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==, + } + + "@shikijs/types@3.22.0": + resolution: + { + integrity: sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==, + } + + "@shikijs/vscode-textmate@10.0.2": + resolution: + { + integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==, + } + + "@types/debug@4.1.12": + resolution: + { + integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, + } + + "@types/estree-jsx@1.0.5": + resolution: + { + integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==, + } + + "@types/estree@1.0.8": + resolution: + { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } + + "@types/hast@3.0.4": + resolution: + { + integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==, + } + + "@types/js-yaml@4.0.9": + resolution: + { + integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==, + } + + "@types/json-schema@7.0.15": + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } + + "@types/mdast@4.0.4": + resolution: + { + integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==, + } + + "@types/mdx@2.0.13": + resolution: + { + integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==, + } + + "@types/ms@2.1.0": + resolution: + { + integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, + } + + "@types/nlcst@2.0.3": + resolution: + { + integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==, + } + + "@types/node@17.0.45": + resolution: + { + integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==, + } + + "@types/sax@1.2.7": + resolution: + { + integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==, + } + + "@types/unist@2.0.11": + resolution: + { + integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, + } + + "@types/unist@3.0.3": + resolution: + { + integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==, + } + + "@ungap/structured-clone@1.3.0": + resolution: + { + integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, + } + + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: + { + integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, + } + engines: { node: ">=0.4.0" } + hasBin: true + + ajv-draft-04@1.0.0: + resolution: + { + integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==, + } + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: + { + integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==, + } + + ansi-align@3.0.1: + resolution: + { + integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==, + } + + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + + ansi-regex@6.2.2: + resolution: + { + integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, + } + engines: { node: ">=12" } + + ansi-styles@6.2.3: + resolution: + { + integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, + } + engines: { node: ">=12" } + + anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } + + arg@5.0.2: + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } + + argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + aria-query@5.3.2: + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: ">= 0.4" } + + array-iterate@2.0.1: + resolution: + { + integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==, + } + + astring@1.9.0: + resolution: + { + integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==, + } + hasBin: true + + astro-expressive-code@0.41.6: + resolution: + { + integrity: sha512-l47tb1uhmVIebHUkw+HEPtU/av0G4O8Q34g2cbkPvC7/e9ZhANcjUUciKt9Hp6gSVDdIuXBBLwJQn2LkeGMOAw==, + } + peerDependencies: + astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta + + astro@5.17.2: + resolution: + { + integrity: sha512-7jnMqGo53hOQNwo1N/wqeOvUp8wwW/p+DeerSjSkHNx8L/1mhy6P7rVo7EhdmF8DpKqw0tl/B5Fx1WcIzg1ysA==, + } + engines: + { node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0" } + hasBin: true + + axobject-query@4.1.0: + resolution: + { + integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, + } + engines: { node: ">= 0.4" } + + bail@2.0.2: + resolution: + { + integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==, + } + + base-64@1.0.0: + resolution: + { + integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==, + } + + bcp-47-match@2.0.3: + resolution: + { + integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==, + } + + bcp-47@2.1.0: + resolution: + { + integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==, + } + + boolbase@1.0.0: + resolution: + { + integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, + } + + boxen@8.0.1: + resolution: + { + integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==, + } + engines: { node: ">=18" } + + camelcase@8.0.0: + resolution: + { + integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==, + } + engines: { node: ">=16" } + + ccount@2.0.1: + resolution: + { + integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==, + } + + chalk@5.6.2: + resolution: + { + integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==, + } + engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } + + character-entities-html4@2.1.0: + resolution: + { + integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==, + } + + character-entities-legacy@3.0.0: + resolution: + { + integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==, + } + + character-entities@2.0.2: + resolution: + { + integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==, + } + + character-reference-invalid@2.0.1: + resolution: + { + integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, + } + + chokidar@5.0.0: + resolution: + { + integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==, + } + engines: { node: ">= 20.19.0" } + + ci-info@4.4.0: + resolution: + { + integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==, + } + engines: { node: ">=8" } + + cli-boxes@3.0.0: + resolution: + { + integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==, + } + engines: { node: ">=10" } + + clsx@2.1.1: + resolution: + { + integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, + } + engines: { node: ">=6" } + + collapse-white-space@2.1.0: + resolution: + { + integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==, + } + + comma-separated-tokens@2.0.3: + resolution: + { + integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==, + } + + commander@11.1.0: + resolution: + { + integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==, + } + engines: { node: ">=16" } + + common-ancestor-path@1.0.1: + resolution: + { + integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==, + } + + cookie-es@1.2.2: + resolution: + { + integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==, + } + + cookie@1.1.1: + resolution: + { + integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==, + } + engines: { node: ">=18" } + + crossws@0.3.5: + resolution: + { + integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==, + } + + css-select@5.2.2: + resolution: + { + integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==, + } + + css-selector-parser@3.3.0: + resolution: + { + integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==, + } + + css-tree@2.2.1: + resolution: + { + integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + + css-tree@3.1.0: + resolution: + { + integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 } + + css-what@6.2.2: + resolution: + { + integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==, + } + engines: { node: ">= 6" } + + cssesc@3.0.0: + resolution: + { + integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, + } + engines: { node: ">=4" } + hasBin: true + + csso@5.0.5: + resolution: + { + integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + + debug@4.4.3: + resolution: + { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: + { + integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==, + } + + defu@6.1.4: + resolution: + { + integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==, + } + + dequal@2.0.3: + resolution: + { + integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, + } + engines: { node: ">=6" } + + destr@2.0.5: + resolution: + { + integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==, + } + + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: ">=8" } + + deterministic-object-hash@2.0.2: + resolution: + { + integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==, + } + engines: { node: ">=18" } + + devalue@5.6.2: + resolution: + { + integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==, + } + + devlop@1.1.0: + resolution: + { + integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==, + } + + diff@8.0.3: + resolution: + { + integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==, + } + engines: { node: ">=0.3.1" } + + direction@2.0.1: + resolution: + { + integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==, + } + hasBin: true + + dlv@1.1.3: + resolution: + { + integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, + } + + dom-serializer@2.0.0: + resolution: + { + integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, + } + + domelementtype@2.3.0: + resolution: + { + integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, + } + + domhandler@5.0.3: + resolution: + { + integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, + } + engines: { node: ">= 4" } + + domutils@3.2.2: + resolution: + { + integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==, + } + + dset@3.1.4: + resolution: + { + integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==, + } + engines: { node: ">=4" } + + emoji-regex@10.6.0: + resolution: + { + integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==, + } + + emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + + entities@4.5.0: + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: ">=0.12" } + + entities@6.0.1: + resolution: + { + integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==, + } + engines: { node: ">=0.12" } + + es-module-lexer@1.7.0: + resolution: + { + integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, + } + + esast-util-from-estree@2.0.0: + resolution: + { + integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==, + } + + esast-util-from-js@2.0.1: + resolution: + { + integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==, + } + + esbuild@0.25.12: + resolution: + { + integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==, + } + engines: { node: ">=18" } + hasBin: true + + esbuild@0.27.3: + resolution: + { + integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==, + } + engines: { node: ">=18" } + hasBin: true + + escape-string-regexp@5.0.0: + resolution: + { + integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==, + } + engines: { node: ">=12" } + + estree-util-attach-comments@3.0.0: + resolution: + { + integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==, + } + + estree-util-build-jsx@3.0.1: + resolution: + { + integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==, + } + + estree-util-is-identifier-name@3.0.0: + resolution: + { + integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==, + } + + estree-util-scope@1.0.0: + resolution: + { + integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==, + } + + estree-util-to-js@2.0.0: + resolution: + { + integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==, + } + + estree-util-visit@2.0.0: + resolution: + { + integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==, + } + + estree-walker@2.0.2: + resolution: + { + integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, + } + + estree-walker@3.0.3: + resolution: + { + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, + } + + eventemitter3@5.0.4: + resolution: + { + integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, + } + + expressive-code@0.41.6: + resolution: + { + integrity: sha512-W/5+IQbrpCIM5KGLjO35wlp1NCwDOOVQb+PAvzEoGkW1xjGM807ZGfBKptNWH6UECvt6qgmLyWolCMYKh7eQmA==, + } + + extend@3.0.2: + resolution: + { + integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==, + } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-uri@3.1.0: + resolution: + { + integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==, + } + + fdir@6.5.0: + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + flattie@1.1.1: + resolution: + { + integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==, + } + engines: { node: ">=8" } + + fontace@0.4.1: + resolution: + { + integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==, + } + + fontkitten@1.0.2: + resolution: + { + integrity: sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q==, + } + engines: { node: ">=20" } + + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + + get-east-asian-width@1.4.0: + resolution: + { + integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==, + } + engines: { node: ">=18" } + + github-slugger@2.0.0: + resolution: + { + integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==, + } + + h3@1.15.5: + resolution: + { + integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==, + } + + hast-util-embedded@3.0.0: + resolution: + { + integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==, + } + + hast-util-format@1.1.0: + resolution: + { + integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==, + } + + hast-util-from-html@2.0.3: + resolution: + { + integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==, + } + + hast-util-from-parse5@8.0.3: + resolution: + { + integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==, + } + + hast-util-has-property@3.0.0: + resolution: + { + integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==, + } + + hast-util-is-body-ok-link@3.0.1: + resolution: + { + integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==, + } + + hast-util-is-element@3.0.0: + resolution: + { + integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==, + } + + hast-util-minify-whitespace@1.0.1: + resolution: + { + integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==, + } + + hast-util-parse-selector@4.0.0: + resolution: + { + integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==, + } + + hast-util-phrasing@3.0.1: + resolution: + { + integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==, + } + + hast-util-raw@9.1.0: + resolution: + { + integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==, + } + + hast-util-select@6.0.4: + resolution: + { + integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==, + } + + hast-util-to-estree@3.1.3: + resolution: + { + integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==, + } + + hast-util-to-html@9.0.5: + resolution: + { + integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==, + } + + hast-util-to-jsx-runtime@2.3.6: + resolution: + { + integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==, + } + + hast-util-to-parse5@8.0.1: + resolution: + { + integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==, + } + + hast-util-to-string@3.0.1: + resolution: + { + integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==, + } + + hast-util-to-text@4.0.2: + resolution: + { + integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==, + } + + hast-util-whitespace@3.0.0: + resolution: + { + integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==, + } + + hastscript@9.0.1: + resolution: + { + integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==, + } + + html-escaper@3.0.3: + resolution: + { + integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==, + } + + html-void-elements@3.0.0: + resolution: + { + integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==, + } + + html-whitespace-sensitive-tag-names@3.0.1: + resolution: + { + integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==, + } + + http-cache-semantics@4.2.0: + resolution: + { + integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, + } + + i18next@23.16.8: + resolution: + { + integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==, + } + + import-meta-resolve@4.2.0: + resolution: + { + integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==, + } + + inline-style-parser@0.2.7: + resolution: + { + integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==, + } + + iron-webcrypto@1.2.1: + resolution: + { + integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==, + } + + is-alphabetical@2.0.1: + resolution: + { + integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==, + } + + is-alphanumerical@2.0.1: + resolution: + { + integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==, + } + + is-decimal@2.0.1: + resolution: + { + integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==, + } + + is-docker@3.0.0: + resolution: + { + integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: ">=8" } + + is-hexadecimal@2.0.1: + resolution: + { + integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==, + } + + is-inside-container@1.0.0: + resolution: + { + integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==, + } + engines: { node: ">=14.16" } + hasBin: true + + is-plain-obj@4.1.0: + resolution: + { + integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==, + } + engines: { node: ">=12" } + + is-wsl@3.1.1: + resolution: + { + integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==, + } + engines: { node: ">=16" } + + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@4.1.1: + resolution: + { + integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, + } + hasBin: true + + json-schema-traverse@1.0.0: + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } + + jsonpointer@5.0.1: + resolution: + { + integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==, + } + engines: { node: ">=0.10.0" } + + kleur@3.0.3: + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: ">=6" } + + klona@2.0.6: + resolution: + { + integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==, + } + engines: { node: ">= 8" } + + leven@3.1.0: + resolution: + { + integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, + } + engines: { node: ">=6" } + + longest-streak@3.1.0: + resolution: + { + integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, + } + + lru-cache@11.2.6: + resolution: + { + integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==, + } + engines: { node: 20 || >=22 } + + magic-string@0.30.21: + resolution: + { + integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==, + } + + magicast@0.5.2: + resolution: + { + integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==, + } + + markdown-extensions@2.0.0: + resolution: + { + integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==, + } + engines: { node: ">=16" } + + markdown-table@3.0.4: + resolution: + { + integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==, + } + + mdast-util-definitions@6.0.0: + resolution: + { + integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==, + } + + mdast-util-directive@3.1.0: + resolution: + { + integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==, + } + + mdast-util-find-and-replace@3.0.2: + resolution: + { + integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==, + } + + mdast-util-from-markdown@2.0.2: + resolution: + { + integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==, + } + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: + { + integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==, + } + + mdast-util-gfm-footnote@2.1.0: + resolution: + { + integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==, + } + + mdast-util-gfm-strikethrough@2.0.0: + resolution: + { + integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==, + } + + mdast-util-gfm-table@2.0.0: + resolution: + { + integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==, + } + + mdast-util-gfm-task-list-item@2.0.0: + resolution: + { + integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==, + } + + mdast-util-gfm@3.1.0: + resolution: + { + integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==, + } + + mdast-util-mdx-expression@2.0.1: + resolution: + { + integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==, + } + + mdast-util-mdx-jsx@3.2.0: + resolution: + { + integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==, + } + + mdast-util-mdx@3.0.0: + resolution: + { + integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==, + } + + mdast-util-mdxjs-esm@2.0.1: + resolution: + { + integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==, + } + + mdast-util-phrasing@4.1.0: + resolution: + { + integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, + } + + mdast-util-to-hast@13.2.1: + resolution: + { + integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==, + } + + mdast-util-to-markdown@2.1.2: + resolution: + { + integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, + } + + mdast-util-to-string@4.0.0: + resolution: + { + integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, + } + + mdn-data@2.0.28: + resolution: + { + integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==, + } + + mdn-data@2.12.2: + resolution: + { + integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==, + } + + micromark-core-commonmark@2.0.3: + resolution: + { + integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, + } + + micromark-extension-directive@3.0.2: + resolution: + { + integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==, + } + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: + { + integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==, + } + + micromark-extension-gfm-footnote@2.1.0: + resolution: + { + integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==, + } + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: + { + integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==, + } + + micromark-extension-gfm-table@2.1.1: + resolution: + { + integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==, + } + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: + { + integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==, + } + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: + { + integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==, + } + + micromark-extension-gfm@3.0.0: + resolution: + { + integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==, + } + + micromark-extension-mdx-expression@3.0.1: + resolution: + { + integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==, + } + + micromark-extension-mdx-jsx@3.0.2: + resolution: + { + integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==, + } + + micromark-extension-mdx-md@2.0.0: + resolution: + { + integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==, + } + + micromark-extension-mdxjs-esm@3.0.0: + resolution: + { + integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==, + } + + micromark-extension-mdxjs@3.0.0: + resolution: + { + integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==, + } + + micromark-factory-destination@2.0.1: + resolution: + { + integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, + } + + micromark-factory-label@2.0.1: + resolution: + { + integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, + } + + micromark-factory-mdx-expression@2.0.3: + resolution: + { + integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==, + } + + micromark-factory-space@2.0.1: + resolution: + { + integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, + } + + micromark-factory-title@2.0.1: + resolution: + { + integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, + } + + micromark-factory-whitespace@2.0.1: + resolution: + { + integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, + } + + micromark-util-character@2.1.1: + resolution: + { + integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==, + } + + micromark-util-chunked@2.0.1: + resolution: + { + integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, + } + + micromark-util-classify-character@2.0.1: + resolution: + { + integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, + } + + micromark-util-combine-extensions@2.0.1: + resolution: + { + integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, + } + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: + { + integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, + } + + micromark-util-decode-string@2.0.1: + resolution: + { + integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, + } + + micromark-util-encode@2.0.1: + resolution: + { + integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==, + } + + micromark-util-events-to-acorn@2.0.3: + resolution: + { + integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==, + } + + micromark-util-html-tag-name@2.0.1: + resolution: + { + integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, + } + + micromark-util-normalize-identifier@2.0.1: + resolution: + { + integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, + } + + micromark-util-resolve-all@2.0.1: + resolution: + { + integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, + } + + micromark-util-sanitize-uri@2.0.1: + resolution: + { + integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==, + } + + micromark-util-subtokenize@2.1.0: + resolution: + { + integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, + } + + micromark-util-symbol@2.0.1: + resolution: + { + integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==, + } + + micromark-util-types@2.0.2: + resolution: + { + integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==, + } + + micromark@4.0.2: + resolution: + { + integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, + } + + mrmime@2.0.1: + resolution: + { + integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==, + } + engines: { node: ">=10" } + + ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + + neotraverse@0.6.18: + resolution: + { + integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==, + } + engines: { node: ">= 10" } + + nlcst-to-string@4.0.0: + resolution: + { + integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==, + } + + node-fetch-native@1.6.7: + resolution: + { + integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==, + } + + node-mock-http@1.0.4: + resolution: + { + integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==, + } + + normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } + + nth-check@2.1.1: + resolution: + { + integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, + } + + ofetch@1.5.1: + resolution: + { + integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==, + } + + ohash@2.0.11: + resolution: + { + integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==, + } + + oniguruma-parser@0.12.1: + resolution: + { + integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==, + } + + oniguruma-to-es@4.3.4: + resolution: + { + integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==, + } + + openapi-types@12.1.3: + resolution: + { + integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==, + } + + p-limit@6.2.0: + resolution: + { + integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==, + } + engines: { node: ">=18" } + + p-queue@8.1.1: + resolution: + { + integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==, + } + engines: { node: ">=18" } + + p-timeout@6.1.4: + resolution: + { + integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==, + } + engines: { node: ">=14.16" } + + package-manager-detector@1.6.0: + resolution: + { + integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==, + } + + pagefind@1.4.0: + resolution: + { + integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==, + } + hasBin: true + + parse-entities@4.0.2: + resolution: + { + integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, + } + + parse-latin@7.0.0: + resolution: + { + integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==, + } + + parse5@7.3.0: + resolution: + { + integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==, + } + + piccolore@0.1.3: + resolution: + { + integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==, + } + + picocolors@1.1.1: + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } + + picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: ">=8.6" } + + picomatch@4.0.3: + resolution: + { + integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, + } + engines: { node: ">=12" } + + postcss-nested@6.2.0: + resolution: + { + integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, + } + engines: { node: ">=12.0" } + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: + { + integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, + } + engines: { node: ">=4" } + + postcss@8.5.6: + resolution: + { + integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, + } + engines: { node: ^10 || ^12 || >=14 } + + prismjs@1.30.0: + resolution: + { + integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==, + } + engines: { node: ">=6" } + + prompts@2.4.2: + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: ">= 6" } + + property-information@7.1.0: + resolution: + { + integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==, + } + + radix3@1.1.2: + resolution: + { + integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==, + } + + readdirp@5.0.0: + resolution: + { + integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==, + } + engines: { node: ">= 20.19.0" } + + recma-build-jsx@1.0.0: + resolution: + { + integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==, + } + + recma-jsx@1.0.1: + resolution: + { + integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: + { + integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==, + } + + recma-stringify@1.0.0: + resolution: + { + integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==, + } + + regex-recursion@6.0.2: + resolution: + { + integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==, + } + + regex-utilities@2.3.0: + resolution: + { + integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==, + } + + regex@6.1.0: + resolution: + { + integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==, + } + + rehype-expressive-code@0.41.6: + resolution: + { + integrity: sha512-aBMX8kxPtjmDSFUdZlAWJkMvsQ4ZMASfee90JWIAV8tweltXLzkWC3q++43ToTelI8ac5iC0B3/S/Cl4Ql1y2g==, + } + + rehype-format@5.0.1: + resolution: + { + integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==, + } + + rehype-parse@9.0.1: + resolution: + { + integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==, + } + + rehype-raw@7.0.0: + resolution: + { + integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==, + } + + rehype-recma@1.0.0: + resolution: + { + integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==, + } + + rehype-stringify@10.0.1: + resolution: + { + integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==, + } + + rehype@13.0.2: + resolution: + { + integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==, + } + + remark-directive@3.0.1: + resolution: + { + integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==, + } + + remark-gfm@4.0.1: + resolution: + { + integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==, + } + + remark-mdx@3.1.1: + resolution: + { + integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==, + } + + remark-parse@11.0.0: + resolution: + { + integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==, + } + + remark-rehype@11.1.2: + resolution: + { + integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==, + } + + remark-smartypants@3.0.2: + resolution: + { + integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==, + } + engines: { node: ">=16.0.0" } + + remark-stringify@11.0.0: + resolution: + { + integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==, + } + + require-from-string@2.0.2: + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: ">=0.10.0" } + + retext-latin@4.0.0: + resolution: + { + integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==, + } + + retext-smartypants@6.2.0: + resolution: + { + integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==, + } + + retext-stringify@4.0.0: + resolution: + { + integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==, + } + + retext@9.0.0: + resolution: + { + integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==, + } + + rollup@4.57.1: + resolution: + { + integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } + hasBin: true + + sax@1.4.4: + resolution: + { + integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==, + } + engines: { node: ">=11.0.0" } + + semver@7.7.4: + resolution: + { + integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==, + } + engines: { node: ">=10" } + hasBin: true + + sharp@0.34.5: + resolution: + { + integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + + shiki@3.22.0: + resolution: + { + integrity: sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==, + } + + sisteransi@1.0.5: + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } + + sitemap@8.0.2: + resolution: + { + integrity: sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==, + } + engines: { node: ">=14.0.0", npm: ">=6.0.0" } + hasBin: true + + smol-toml@1.6.0: + resolution: + { + integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==, + } + engines: { node: ">= 18" } + + source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: ">=0.10.0" } + + source-map@0.7.6: + resolution: + { + integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==, + } + engines: { node: ">= 12" } + + space-separated-tokens@2.0.2: + resolution: + { + integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==, + } + + starlight-openapi@0.22.0: + resolution: + { + integrity: sha512-4H/fywAoTcvKbcv+xBr9LdrjMc5geDOSnydvzpiOxjxkHvI6g+7uPhWNCejnJPyZUd/MC1MI23tvYug85d/WzA==, + } + engines: { node: ">=18.17.1" } + peerDependencies: + "@astrojs/markdown-remark": ">=6.0.1" + "@astrojs/starlight": ">=0.34.0" + astro: ">=5.5.0" + + stream-replace-string@2.0.0: + resolution: + { + integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==, + } + + string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: ">=8" } + + string-width@7.2.0: + resolution: + { + integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==, + } + engines: { node: ">=18" } + + stringify-entities@4.0.4: + resolution: + { + integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==, + } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + + strip-ansi@7.1.2: + resolution: + { + integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==, + } + engines: { node: ">=12" } + + style-to-js@1.1.21: + resolution: + { + integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==, + } + + style-to-object@1.0.14: + resolution: + { + integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==, + } + + svgo@4.0.0: + resolution: + { + integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==, + } + engines: { node: ">=16" } + hasBin: true + + tiny-inflate@1.0.3: + resolution: + { + integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==, + } + + tinyexec@1.0.2: + resolution: + { + integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==, + } + engines: { node: ">=18" } + + tinyglobby@0.2.15: + resolution: + { + integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, + } + engines: { node: ">=12.0.0" } + + trim-lines@3.0.1: + resolution: + { + integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==, + } + + trough@2.2.0: + resolution: + { + integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==, + } + + tsconfck@3.1.6: + resolution: + { + integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==, + } + engines: { node: ^18 || >=20 } + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } + + type-fest@4.41.0: + resolution: + { + integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, + } + engines: { node: ">=16" } + + typescript@5.9.3: + resolution: + { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: ">=14.17" } + hasBin: true + + ufo@1.6.3: + resolution: + { + integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==, + } + + ultrahtml@1.6.0: + resolution: + { + integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==, + } + + uncrypto@0.1.3: + resolution: + { + integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==, + } + + unified@11.0.5: + resolution: + { + integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==, + } + + unifont@0.7.4: + resolution: + { + integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==, + } + + unist-util-find-after@5.0.0: + resolution: + { + integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==, + } + + unist-util-is@6.0.1: + resolution: + { + integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==, + } + + unist-util-modify-children@4.0.0: + resolution: + { + integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==, + } + + unist-util-position-from-estree@2.0.0: + resolution: + { + integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==, + } + + unist-util-position@5.0.0: + resolution: + { + integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==, + } + + unist-util-remove-position@5.0.0: + resolution: + { + integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==, + } + + unist-util-stringify-position@4.0.0: + resolution: + { + integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==, + } + + unist-util-visit-children@3.0.0: + resolution: + { + integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==, + } + + unist-util-visit-parents@6.0.2: + resolution: + { + integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==, + } + + unist-util-visit@5.1.0: + resolution: + { + integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==, + } + + unstorage@1.17.4: + resolution: + { + integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==, + } + peerDependencies: + "@azure/app-configuration": ^1.8.0 + "@azure/cosmos": ^4.2.0 + "@azure/data-tables": ^13.3.0 + "@azure/identity": ^4.6.0 + "@azure/keyvault-secrets": ^4.9.0 + "@azure/storage-blob": ^12.26.0 + "@capacitor/preferences": ^6 || ^7 || ^8 + "@deno/kv": ">=0.9.0" + "@netlify/blobs": ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + "@planetscale/database": ^1.19.0 + "@upstash/redis": ^1.34.3 + "@vercel/blob": ">=0.27.1" + "@vercel/functions": ^2.2.12 || ^3.0.0 + "@vercel/kv": ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: ">=0.2.1" + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + "@azure/app-configuration": + optional: true + "@azure/cosmos": + optional: true + "@azure/data-tables": + optional: true + "@azure/identity": + optional: true + "@azure/keyvault-secrets": + optional: true + "@azure/storage-blob": + optional: true + "@capacitor/preferences": + optional: true + "@deno/kv": + optional: true + "@netlify/blobs": + optional: true + "@planetscale/database": + optional: true + "@upstash/redis": + optional: true + "@vercel/blob": + optional: true + "@vercel/functions": + optional: true + "@vercel/kv": + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + url-template@3.1.1: + resolution: + { + integrity: sha512-4oszoaEKE/mQOtAmdMWqIRHmkxWkUZMnXFnjQ5i01CuRSK3uluxcH1MRVVVWmhlnzT1SCDfKxxficm2G37qzCA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + + vfile-location@5.0.3: + resolution: + { + integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==, + } + + vfile-message@4.0.3: + resolution: + { + integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==, + } + + vfile@6.0.3: + resolution: + { + integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==, + } + + vite@6.4.1: + resolution: + { + integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==, + } + engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + hasBin: true + peerDependencies: + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: + { + integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==, + } + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + web-namespaces@2.0.1: + resolution: + { + integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==, + } + + which-pm-runs@1.1.0: + resolution: + { + integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==, + } + engines: { node: ">=4" } + + widest-line@5.0.0: + resolution: + { + integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==, + } + engines: { node: ">=18" } + + wrap-ansi@9.0.2: + resolution: + { + integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==, + } + engines: { node: ">=18" } + + xxhash-wasm@1.1.0: + resolution: + { + integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==, + } + + yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: ">=12" } + + yocto-queue@1.2.2: + resolution: + { + integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==, + } + engines: { node: ">=12.20" } + + yocto-spinner@0.2.3: + resolution: + { + integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==, + } + engines: { node: ">=18.19" } + + yoctocolors@2.1.2: + resolution: + { + integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==, + } + engines: { node: ">=18" } + + zod-to-json-schema@3.25.1: + resolution: + { + integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==, + } + peerDependencies: + zod: ^3.25 || ^4 + + zod-to-ts@1.2.0: + resolution: + { + integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==, + } + peerDependencies: + typescript: ^4.9.4 || ^5.0.2 + zod: ^3 + + zod@3.25.76: + resolution: + { + integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, + } + + zwitch@2.0.4: + resolution: + { + integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==, + } + +snapshots: + "@apidevtools/json-schema-ref-parser@13.0.5": + dependencies: + "@types/json-schema": 7.0.15 + js-yaml: 4.1.1 + + "@astrojs/compiler@2.13.1": {} + + "@astrojs/internal-helpers@0.7.5": {} + + "@astrojs/markdown-remark@6.3.10": + dependencies: + "@astrojs/internal-helpers": 0.7.5 + "@astrojs/prism": 3.3.0 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 3.22.0 + smol-toml: 1.6.0 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + "@astrojs/mdx@4.3.13(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3))": + dependencies: + "@astrojs/markdown-remark": 6.3.10 + "@mdx-js/mdx": 3.1.1 + acorn: 8.15.0 + astro: 5.17.2(rollup@4.57.1)(typescript@5.9.3) + es-module-lexer: 1.7.0 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.2 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + "@astrojs/prism@3.3.0": + dependencies: + prismjs: 1.30.0 + + "@astrojs/sitemap@3.7.0": + dependencies: + sitemap: 8.0.2 + stream-replace-string: 2.0.0 + zod: 3.25.76 + + "@astrojs/starlight@0.37.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3))": + dependencies: + "@astrojs/markdown-remark": 6.3.10 + "@astrojs/mdx": 4.3.13(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)) + "@astrojs/sitemap": 3.7.0 + "@pagefind/default-ui": 1.4.0 + "@types/hast": 3.0.4 + "@types/js-yaml": 4.0.9 + "@types/mdast": 4.0.4 + astro: 5.17.2(rollup@4.57.1)(typescript@5.9.3) + astro-expressive-code: 0.41.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)) + bcp-47: 2.1.0 + hast-util-from-html: 2.0.3 + hast-util-select: 6.0.4 + hast-util-to-string: 3.0.1 + hastscript: 9.0.1 + i18next: 23.16.8 + js-yaml: 4.1.1 + klona: 2.0.6 + magic-string: 0.30.21 + mdast-util-directive: 3.1.0 + mdast-util-to-markdown: 2.1.2 + mdast-util-to-string: 4.0.0 + pagefind: 1.4.0 + rehype: 13.0.2 + rehype-format: 5.0.1 + remark-directive: 3.0.1 + ultrahtml: 1.6.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + "@astrojs/telemetry@3.3.0": + dependencies: + ci-info: 4.4.0 + debug: 4.4.3 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.1 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + + "@babel/code-frame@7.29.0": + dependencies: + "@babel/helper-validator-identifier": 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + "@babel/helper-string-parser@7.27.1": {} + + "@babel/helper-validator-identifier@7.28.5": {} + + "@babel/parser@7.29.0": + dependencies: + "@babel/types": 7.29.0 + + "@babel/runtime@7.28.6": {} + + "@babel/types@7.29.0": + dependencies: + "@babel/helper-string-parser": 7.27.1 + "@babel/helper-validator-identifier": 7.28.5 + + "@capsizecss/unpack@4.0.0": + dependencies: + fontkitten: 1.0.2 + + "@ctrl/tinycolor@4.2.0": {} + + "@emnapi/runtime@1.8.1": + dependencies: + tslib: 2.8.1 + optional: true + + "@esbuild/aix-ppc64@0.25.12": + optional: true + + "@esbuild/aix-ppc64@0.27.3": + optional: true + + "@esbuild/android-arm64@0.25.12": + optional: true + + "@esbuild/android-arm64@0.27.3": + optional: true + + "@esbuild/android-arm@0.25.12": + optional: true + + "@esbuild/android-arm@0.27.3": + optional: true + + "@esbuild/android-x64@0.25.12": + optional: true + + "@esbuild/android-x64@0.27.3": + optional: true + + "@esbuild/darwin-arm64@0.25.12": + optional: true + + "@esbuild/darwin-arm64@0.27.3": + optional: true + + "@esbuild/darwin-x64@0.25.12": + optional: true + + "@esbuild/darwin-x64@0.27.3": + optional: true + + "@esbuild/freebsd-arm64@0.25.12": + optional: true + + "@esbuild/freebsd-arm64@0.27.3": + optional: true + + "@esbuild/freebsd-x64@0.25.12": + optional: true + + "@esbuild/freebsd-x64@0.27.3": + optional: true + + "@esbuild/linux-arm64@0.25.12": + optional: true + + "@esbuild/linux-arm64@0.27.3": + optional: true + + "@esbuild/linux-arm@0.25.12": + optional: true + + "@esbuild/linux-arm@0.27.3": + optional: true + + "@esbuild/linux-ia32@0.25.12": + optional: true + + "@esbuild/linux-ia32@0.27.3": + optional: true + + "@esbuild/linux-loong64@0.25.12": + optional: true + + "@esbuild/linux-loong64@0.27.3": + optional: true + + "@esbuild/linux-mips64el@0.25.12": + optional: true + + "@esbuild/linux-mips64el@0.27.3": + optional: true + + "@esbuild/linux-ppc64@0.25.12": + optional: true + + "@esbuild/linux-ppc64@0.27.3": + optional: true + + "@esbuild/linux-riscv64@0.25.12": + optional: true + + "@esbuild/linux-riscv64@0.27.3": + optional: true + + "@esbuild/linux-s390x@0.25.12": + optional: true + + "@esbuild/linux-s390x@0.27.3": + optional: true + + "@esbuild/linux-x64@0.25.12": + optional: true + + "@esbuild/linux-x64@0.27.3": + optional: true + + "@esbuild/netbsd-arm64@0.25.12": + optional: true + + "@esbuild/netbsd-arm64@0.27.3": + optional: true + + "@esbuild/netbsd-x64@0.25.12": + optional: true + + "@esbuild/netbsd-x64@0.27.3": + optional: true + + "@esbuild/openbsd-arm64@0.25.12": + optional: true + + "@esbuild/openbsd-arm64@0.27.3": + optional: true + + "@esbuild/openbsd-x64@0.25.12": + optional: true + + "@esbuild/openbsd-x64@0.27.3": + optional: true + + "@esbuild/openharmony-arm64@0.25.12": + optional: true + + "@esbuild/openharmony-arm64@0.27.3": + optional: true + + "@esbuild/sunos-x64@0.25.12": + optional: true + + "@esbuild/sunos-x64@0.27.3": + optional: true + + "@esbuild/win32-arm64@0.25.12": + optional: true + + "@esbuild/win32-arm64@0.27.3": + optional: true + + "@esbuild/win32-ia32@0.25.12": + optional: true + + "@esbuild/win32-ia32@0.27.3": + optional: true + + "@esbuild/win32-x64@0.25.12": + optional: true + + "@esbuild/win32-x64@0.27.3": + optional: true + + "@expressive-code/core@0.41.6": + dependencies: + "@ctrl/tinycolor": 4.2.0 + hast-util-select: 6.0.4 + hast-util-to-html: 9.0.5 + hast-util-to-text: 4.0.2 + hastscript: 9.0.1 + postcss: 8.5.6 + postcss-nested: 6.2.0(postcss@8.5.6) + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + + "@expressive-code/plugin-frames@0.41.6": + dependencies: + "@expressive-code/core": 0.41.6 + + "@expressive-code/plugin-shiki@0.41.6": + dependencies: + "@expressive-code/core": 0.41.6 + shiki: 3.22.0 + + "@expressive-code/plugin-text-markers@0.41.6": + dependencies: + "@expressive-code/core": 0.41.6 + + "@fontsource/inter@5.2.8": {} + + "@fontsource/rubik@5.2.8": {} + + "@humanwhocodes/momoa@2.0.4": {} + + "@img/colour@1.0.0": {} + + "@img/sharp-darwin-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-darwin-arm64": 1.2.4 + optional: true + + "@img/sharp-darwin-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-darwin-x64": 1.2.4 + optional: true + + "@img/sharp-libvips-darwin-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-darwin-x64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-arm@1.2.4": + optional: true + + "@img/sharp-libvips-linux-ppc64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-riscv64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-s390x@1.2.4": + optional: true + + "@img/sharp-libvips-linux-x64@1.2.4": + optional: true + + "@img/sharp-libvips-linuxmusl-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-linuxmusl-x64@1.2.4": + optional: true + + "@img/sharp-linux-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm64": 1.2.4 + optional: true + + "@img/sharp-linux-arm@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm": 1.2.4 + optional: true + + "@img/sharp-linux-ppc64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-ppc64": 1.2.4 + optional: true + + "@img/sharp-linux-riscv64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-riscv64": 1.2.4 + optional: true + + "@img/sharp-linux-s390x@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-s390x": 1.2.4 + optional: true + + "@img/sharp-linux-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-x64": 1.2.4 + optional: true + + "@img/sharp-linuxmusl-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + optional: true + + "@img/sharp-linuxmusl-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + optional: true + + "@img/sharp-wasm32@0.34.5": + dependencies: + "@emnapi/runtime": 1.8.1 + optional: true + + "@img/sharp-win32-arm64@0.34.5": + optional: true + + "@img/sharp-win32-ia32@0.34.5": + optional: true + + "@img/sharp-win32-x64@0.34.5": + optional: true + + "@jridgewell/sourcemap-codec@1.5.5": {} + + "@mdx-js/mdx@3.1.1": + dependencies: + "@types/estree": 1.0.8 + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdx": 2.0.13 + acorn: 8.15.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.15.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + "@oslojs/encoding@1.1.0": {} + + "@pagefind/darwin-arm64@1.4.0": + optional: true + + "@pagefind/darwin-x64@1.4.0": + optional: true + + "@pagefind/default-ui@1.4.0": {} + + "@pagefind/freebsd-x64@1.4.0": + optional: true + + "@pagefind/linux-arm64@1.4.0": + optional: true + + "@pagefind/linux-x64@1.4.0": + optional: true + + "@pagefind/windows-x64@1.4.0": + optional: true + + "@readme/better-ajv-errors@2.4.0(ajv@8.18.0)": + dependencies: + "@babel/code-frame": 7.29.0 + "@babel/runtime": 7.28.6 + "@humanwhocodes/momoa": 2.0.4 + ajv: 8.18.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + picocolors: 1.1.1 + + "@readme/openapi-parser@4.1.2(openapi-types@12.1.3)": + dependencies: + "@apidevtools/json-schema-ref-parser": 13.0.5 + "@readme/better-ajv-errors": 2.4.0(ajv@8.18.0) + "@readme/openapi-schemas": 3.1.0 + "@types/json-schema": 7.0.15 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + openapi-types: 12.1.3 + + "@readme/openapi-schemas@3.1.0": {} + + "@rollup/pluginutils@5.3.0(rollup@4.57.1)": + dependencies: + "@types/estree": 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.57.1 + + "@rollup/rollup-android-arm-eabi@4.57.1": + optional: true + + "@rollup/rollup-android-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-x64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-arm64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-x64@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-musleabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-s390x-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-musl@4.57.1": + optional: true + + "@rollup/rollup-openbsd-x64@4.57.1": + optional: true + + "@rollup/rollup-openharmony-arm64@4.57.1": + optional: true + + "@rollup/rollup-win32-arm64-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-ia32-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-msvc@4.57.1": + optional: true + + "@shikijs/core@3.22.0": + dependencies: + "@shikijs/types": 3.22.0 + "@shikijs/vscode-textmate": 10.0.2 + "@types/hast": 3.0.4 + hast-util-to-html: 9.0.5 + + "@shikijs/engine-javascript@3.22.0": + dependencies: + "@shikijs/types": 3.22.0 + "@shikijs/vscode-textmate": 10.0.2 + oniguruma-to-es: 4.3.4 + + "@shikijs/engine-oniguruma@3.22.0": + dependencies: + "@shikijs/types": 3.22.0 + "@shikijs/vscode-textmate": 10.0.2 + + "@shikijs/langs@3.22.0": + dependencies: + "@shikijs/types": 3.22.0 + + "@shikijs/themes@3.22.0": + dependencies: + "@shikijs/types": 3.22.0 + + "@shikijs/types@3.22.0": + dependencies: + "@shikijs/vscode-textmate": 10.0.2 + "@types/hast": 3.0.4 + + "@shikijs/vscode-textmate@10.0.2": {} + + "@types/debug@4.1.12": + dependencies: + "@types/ms": 2.1.0 + + "@types/estree-jsx@1.0.5": + dependencies: + "@types/estree": 1.0.8 + + "@types/estree@1.0.8": {} + + "@types/hast@3.0.4": + dependencies: + "@types/unist": 3.0.3 + + "@types/js-yaml@4.0.9": {} + + "@types/json-schema@7.0.15": {} + + "@types/mdast@4.0.4": + dependencies: + "@types/unist": 3.0.3 + + "@types/mdx@2.0.13": {} + + "@types/ms@2.1.0": {} + + "@types/nlcst@2.0.3": + dependencies: + "@types/unist": 3.0.3 + + "@types/node@17.0.45": {} + + "@types/sax@1.2.7": + dependencies: + "@types/node": 17.0.45 + + "@types/unist@2.0.11": {} + + "@types/unist@3.0.3": {} + + "@ungap/structured-clone@1.3.0": {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@6.2.3: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-iterate@2.0.1: {} + + astring@1.9.0: {} + + astro-expressive-code@0.41.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)): + dependencies: + astro: 5.17.2(rollup@4.57.1)(typescript@5.9.3) + rehype-expressive-code: 0.41.6 + + astro@5.17.2(rollup@4.57.1)(typescript@5.9.3): + dependencies: + "@astrojs/compiler": 2.13.1 + "@astrojs/internal-helpers": 0.7.5 + "@astrojs/markdown-remark": 6.3.10 + "@astrojs/telemetry": 3.3.0 + "@capsizecss/unpack": 4.0.0 + "@oslojs/encoding": 1.1.0 + "@rollup/pluginutils": 5.3.0(rollup@4.57.1) + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + boxen: 8.0.1 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 1.0.1 + cookie: 1.1.1 + cssesc: 3.0.0 + debug: 4.4.3 + deterministic-object-hash: 2.0.2 + devalue: 5.6.2 + diff: 8.0.3 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 1.7.0 + esbuild: 0.27.3 + estree-walker: 3.0.3 + flattie: 1.1.1 + fontace: 0.4.1 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + import-meta-resolve: 4.2.0 + js-yaml: 4.1.1 + magic-string: 0.30.21 + magicast: 0.5.2 + mrmime: 2.0.1 + neotraverse: 0.6.18 + p-limit: 6.2.0 + p-queue: 8.1.1 + package-manager-detector: 1.6.0 + piccolore: 0.1.3 + picomatch: 4.0.3 + prompts: 2.4.2 + rehype: 13.0.2 + semver: 7.7.4 + shiki: 3.22.0 + smol-toml: 1.6.0 + svgo: 4.0.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.7.4 + unist-util-visit: 5.1.0 + unstorage: 1.17.4 + vfile: 6.0.3 + vite: 6.4.1 + vitefu: 1.1.1(vite@6.4.1) + xxhash-wasm: 1.1.0 + yargs-parser: 21.1.1 + yocto-spinner: 0.2.3 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - "@azure/app-configuration" + - "@azure/cosmos" + - "@azure/data-tables" + - "@azure/identity" + - "@azure/keyvault-secrets" + - "@azure/storage-blob" + - "@capacitor/preferences" + - "@deno/kv" + - "@netlify/blobs" + - "@planetscale/database" + - "@types/node" + - "@upstash/redis" + - "@vercel/blob" + - "@vercel/functions" + - "@vercel/kv" + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + base-64@1.0.0: {} + + bcp-47-match@2.0.3: {} + + bcp-47@2.1.0: + dependencies: + is-alphabetical: 2.0.1 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + + camelcase@8.0.0: {} + + ccount@2.0.1: {} + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} + + cli-boxes@3.0.0: {} + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + common-ancestor-path@1.0.1: {} + + cookie-es@1.2.2: {} + + cookie@1.1.1: {} + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-selector-parser@3.3.0: {} + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + defu@6.1.4: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + deterministic-object-hash@2.0.2: + dependencies: + base-64: 1.0.0 + + devalue@5.6.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.3: {} + + direction@2.0.1: {} + + dlv@1.1.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + es-module-lexer@1.7.0: {} + + esast-util-from-estree@2.0.0: + dependencies: + "@types/estree-jsx": 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + acorn: 8.15.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.25.12: + optionalDependencies: + "@esbuild/aix-ppc64": 0.25.12 + "@esbuild/android-arm": 0.25.12 + "@esbuild/android-arm64": 0.25.12 + "@esbuild/android-x64": 0.25.12 + "@esbuild/darwin-arm64": 0.25.12 + "@esbuild/darwin-x64": 0.25.12 + "@esbuild/freebsd-arm64": 0.25.12 + "@esbuild/freebsd-x64": 0.25.12 + "@esbuild/linux-arm": 0.25.12 + "@esbuild/linux-arm64": 0.25.12 + "@esbuild/linux-ia32": 0.25.12 + "@esbuild/linux-loong64": 0.25.12 + "@esbuild/linux-mips64el": 0.25.12 + "@esbuild/linux-ppc64": 0.25.12 + "@esbuild/linux-riscv64": 0.25.12 + "@esbuild/linux-s390x": 0.25.12 + "@esbuild/linux-x64": 0.25.12 + "@esbuild/netbsd-arm64": 0.25.12 + "@esbuild/netbsd-x64": 0.25.12 + "@esbuild/openbsd-arm64": 0.25.12 + "@esbuild/openbsd-x64": 0.25.12 + "@esbuild/openharmony-arm64": 0.25.12 + "@esbuild/sunos-x64": 0.25.12 + "@esbuild/win32-arm64": 0.25.12 + "@esbuild/win32-ia32": 0.25.12 + "@esbuild/win32-x64": 0.25.12 + + esbuild@0.27.3: + optionalDependencies: + "@esbuild/aix-ppc64": 0.27.3 + "@esbuild/android-arm": 0.27.3 + "@esbuild/android-arm64": 0.27.3 + "@esbuild/android-x64": 0.27.3 + "@esbuild/darwin-arm64": 0.27.3 + "@esbuild/darwin-x64": 0.27.3 + "@esbuild/freebsd-arm64": 0.27.3 + "@esbuild/freebsd-x64": 0.27.3 + "@esbuild/linux-arm": 0.27.3 + "@esbuild/linux-arm64": 0.27.3 + "@esbuild/linux-ia32": 0.27.3 + "@esbuild/linux-loong64": 0.27.3 + "@esbuild/linux-mips64el": 0.27.3 + "@esbuild/linux-ppc64": 0.27.3 + "@esbuild/linux-riscv64": 0.27.3 + "@esbuild/linux-s390x": 0.27.3 + "@esbuild/linux-x64": 0.27.3 + "@esbuild/netbsd-arm64": 0.27.3 + "@esbuild/netbsd-x64": 0.27.3 + "@esbuild/openbsd-arm64": 0.27.3 + "@esbuild/openbsd-x64": 0.27.3 + "@esbuild/openharmony-arm64": 0.27.3 + "@esbuild/sunos-x64": 0.27.3 + "@esbuild/win32-arm64": 0.27.3 + "@esbuild/win32-ia32": 0.27.3 + "@esbuild/win32-x64": 0.27.3 + + escape-string-regexp@5.0.0: {} + + estree-util-attach-comments@3.0.0: + dependencies: + "@types/estree": 1.0.8 + + estree-util-build-jsx@3.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + "@types/estree": 1.0.8 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + "@types/estree-jsx": 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-visit@2.0.0: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/unist": 3.0.3 + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + "@types/estree": 1.0.8 + + eventemitter3@5.0.4: {} + + expressive-code@0.41.6: + dependencies: + "@expressive-code/core": 0.41.6 + "@expressive-code/plugin-frames": 0.41.6 + "@expressive-code/plugin-shiki": 0.41.6 + "@expressive-code/plugin-text-markers": 0.41.6 + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + flattie@1.1.1: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.2 + + fontkitten@1.0.2: + dependencies: + tiny-inflate: 1.0.3 + + fsevents@2.3.3: + optional: true + + get-east-asian-width@1.4.0: {} + + github-slugger@2.0.0: {} + + h3@1.15.5: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 + + hast-util-embedded@3.0.0: + dependencies: + "@types/hast": 3.0.4 + hast-util-is-element: 3.0.0 + + hast-util-format@1.1.0: + dependencies: + "@types/hast": 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-minify-whitespace: 1.0.1 + hast-util-phrasing: 3.0.1 + hast-util-whitespace: 3.0.0 + html-whitespace-sensitive-tag-names: 3.0.1 + unist-util-visit-parents: 6.0.2 + + hast-util-from-html@2.0.3: + dependencies: + "@types/hast": 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + "@types/hast": 3.0.4 + + hast-util-is-body-ok-link@3.0.1: + dependencies: + "@types/hast": 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + "@types/hast": 3.0.4 + + hast-util-minify-whitespace@1.0.1: + dependencies: + "@types/hast": 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-is-element: 3.0.0 + hast-util-whitespace: 3.0.0 + unist-util-is: 6.0.1 + + hast-util-parse-selector@4.0.0: + dependencies: + "@types/hast": 3.0.4 + + hast-util-phrasing@3.0.1: + dependencies: + "@types/hast": 3.0.4 + hast-util-embedded: 3.0.0 + hast-util-has-property: 3.0.0 + hast-util-is-body-ok-link: 3.0.1 + hast-util-is-element: 3.0.0 + + hast-util-raw@9.1.0: + dependencies: + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + "@ungap/structured-clone": 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-select@6.0.4: + dependencies: + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.3.0 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + "@types/estree": 1.0.8 + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + "@types/estree": 1.0.8 + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + "@types/hast": 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + "@types/hast": 3.0.4 + + hast-util-to-text@4.0.2: + dependencies: + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + "@types/hast": 3.0.4 + + hastscript@9.0.1: + dependencies: + "@types/hast": 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + html-whitespace-sensitive-tag-names@3.0.1: {} + + http-cache-semantics@4.2.0: {} + + i18next@23.16.8: + dependencies: + "@babel/runtime": 7.28.6 + + import-meta-resolve@4.2.0: {} + + inline-style-parser@0.2.7: {} + + iron-webcrypto@1.2.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-docker@3.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-hexadecimal@2.0.1: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-plain-obj@4.1.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-schema-traverse@1.0.0: {} + + jsonpointer@5.0.1: {} + + kleur@3.0.3: {} + + klona@2.0.6: {} + + leven@3.1.0: {} + + longest-streak@3.1.0: {} + + lru-cache@11.2.6: {} + + magic-string@0.30.21: + dependencies: + "@jridgewell/sourcemap-codec": 1.5.5 + + magicast@0.5.2: + dependencies: + "@babel/parser": 7.29.0 + "@babel/types": 7.29.0 + source-map-js: 1.2.1 + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + mdast-util-definitions@6.0.0: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-directive@3.1.0: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + "@types/mdast": 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + "@types/mdast": 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + "@types/mdast": 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + "@types/mdast": 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + "@ungap/structured-clone": 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + "@types/mdast": 4.0.4 + + mdn-data@2.0.28: {} + + mdn-data@2.12.2: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-directive@3.0.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + "@types/estree": 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + "@types/estree": 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + "@types/estree": 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + "@types/estree": 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + "@types/estree": 1.0.8 + "@types/unist": 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + "@types/debug": 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + neotraverse@0.6.18: {} + + nlcst-to-string@4.0.0: + dependencies: + "@types/nlcst": 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.4: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.3 + + ohash@2.0.11: {} + + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + + openapi-types@12.1.3: {} + + p-limit@6.2.0: + dependencies: + yocto-queue: 1.2.2 + + p-queue@8.1.1: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 6.1.4 + + p-timeout@6.1.4: {} + + package-manager-detector@1.6.0: {} + + pagefind@1.4.0: + optionalDependencies: + "@pagefind/darwin-arm64": 1.4.0 + "@pagefind/darwin-x64": 1.4.0 + "@pagefind/freebsd-x64": 1.4.0 + "@pagefind/linux-arm64": 1.4.0 + "@pagefind/linux-x64": 1.4.0 + "@pagefind/windows-x64": 1.4.0 + + parse-entities@4.0.2: + dependencies: + "@types/unist": 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-latin@7.0.0: + dependencies: + "@types/nlcst": 2.0.3 + "@types/unist": 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + postcss-nested@6.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prismjs@1.30.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + property-information@7.1.0: {} + + radix3@1.1.2: {} + + readdirp@5.0.0: {} + + recma-build-jsx@1.0.0: + dependencies: + "@types/estree": 1.0.8 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + "@types/estree": 1.0.8 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + "@types/estree": 1.0.8 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-expressive-code@0.41.6: + dependencies: + expressive-code: 0.41.6 + + rehype-format@5.0.1: + dependencies: + "@types/hast": 3.0.4 + hast-util-format: 1.1.0 + + rehype-parse@9.0.1: + dependencies: + "@types/hast": 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + "@types/hast": 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-recma@1.0.0: + dependencies: + "@types/estree": 1.0.8 + "@types/hast": 3.0.4 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + rehype-stringify@10.0.1: + dependencies: + "@types/hast": 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + "@types/hast": 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-directive@3.0.1: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-directive: 3.1.0 + micromark-extension-directive: 3.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + remark-stringify@11.0.0: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + require-from-string@2.0.2: {} + + retext-latin@4.0.0: + dependencies: + "@types/nlcst": 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + "@types/nlcst": 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + "@types/nlcst": 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + "@types/nlcst": 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + rollup@4.57.1: + dependencies: + "@types/estree": 1.0.8 + optionalDependencies: + "@rollup/rollup-android-arm-eabi": 4.57.1 + "@rollup/rollup-android-arm64": 4.57.1 + "@rollup/rollup-darwin-arm64": 4.57.1 + "@rollup/rollup-darwin-x64": 4.57.1 + "@rollup/rollup-freebsd-arm64": 4.57.1 + "@rollup/rollup-freebsd-x64": 4.57.1 + "@rollup/rollup-linux-arm-gnueabihf": 4.57.1 + "@rollup/rollup-linux-arm-musleabihf": 4.57.1 + "@rollup/rollup-linux-arm64-gnu": 4.57.1 + "@rollup/rollup-linux-arm64-musl": 4.57.1 + "@rollup/rollup-linux-loong64-gnu": 4.57.1 + "@rollup/rollup-linux-loong64-musl": 4.57.1 + "@rollup/rollup-linux-ppc64-gnu": 4.57.1 + "@rollup/rollup-linux-ppc64-musl": 4.57.1 + "@rollup/rollup-linux-riscv64-gnu": 4.57.1 + "@rollup/rollup-linux-riscv64-musl": 4.57.1 + "@rollup/rollup-linux-s390x-gnu": 4.57.1 + "@rollup/rollup-linux-x64-gnu": 4.57.1 + "@rollup/rollup-linux-x64-musl": 4.57.1 + "@rollup/rollup-openbsd-x64": 4.57.1 + "@rollup/rollup-openharmony-arm64": 4.57.1 + "@rollup/rollup-win32-arm64-msvc": 4.57.1 + "@rollup/rollup-win32-ia32-msvc": 4.57.1 + "@rollup/rollup-win32-x64-gnu": 4.57.1 + "@rollup/rollup-win32-x64-msvc": 4.57.1 + fsevents: 2.3.3 + + sax@1.4.4: {} + + semver@7.7.4: {} + + sharp@0.34.5: + dependencies: + "@img/colour": 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + "@img/sharp-darwin-arm64": 0.34.5 + "@img/sharp-darwin-x64": 0.34.5 + "@img/sharp-libvips-darwin-arm64": 1.2.4 + "@img/sharp-libvips-darwin-x64": 1.2.4 + "@img/sharp-libvips-linux-arm": 1.2.4 + "@img/sharp-libvips-linux-arm64": 1.2.4 + "@img/sharp-libvips-linux-ppc64": 1.2.4 + "@img/sharp-libvips-linux-riscv64": 1.2.4 + "@img/sharp-libvips-linux-s390x": 1.2.4 + "@img/sharp-libvips-linux-x64": 1.2.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + "@img/sharp-linux-arm": 0.34.5 + "@img/sharp-linux-arm64": 0.34.5 + "@img/sharp-linux-ppc64": 0.34.5 + "@img/sharp-linux-riscv64": 0.34.5 + "@img/sharp-linux-s390x": 0.34.5 + "@img/sharp-linux-x64": 0.34.5 + "@img/sharp-linuxmusl-arm64": 0.34.5 + "@img/sharp-linuxmusl-x64": 0.34.5 + "@img/sharp-wasm32": 0.34.5 + "@img/sharp-win32-arm64": 0.34.5 + "@img/sharp-win32-ia32": 0.34.5 + "@img/sharp-win32-x64": 0.34.5 + + shiki@3.22.0: + dependencies: + "@shikijs/core": 3.22.0 + "@shikijs/engine-javascript": 3.22.0 + "@shikijs/engine-oniguruma": 3.22.0 + "@shikijs/langs": 3.22.0 + "@shikijs/themes": 3.22.0 + "@shikijs/types": 3.22.0 + "@shikijs/vscode-textmate": 10.0.2 + "@types/hast": 3.0.4 + + sisteransi@1.0.5: {} + + sitemap@8.0.2: + dependencies: + "@types/node": 17.0.45 + "@types/sax": 1.2.7 + arg: 5.0.2 + sax: 1.4.4 + + smol-toml@1.6.0: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + starlight-openapi@0.22.0(@astrojs/markdown-remark@6.3.10)(@astrojs/starlight@0.37.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)))(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3))(openapi-types@12.1.3): + dependencies: + "@astrojs/markdown-remark": 6.3.10 + "@astrojs/starlight": 0.37.6(astro@5.17.2(rollup@4.57.1)(typescript@5.9.3)) + "@readme/openapi-parser": 4.1.2(openapi-types@12.1.3) + astro: 5.17.2(rollup@4.57.1)(typescript@5.9.3) + github-slugger: 2.0.0 + url-template: 3.1.1 + transitivePeerDependencies: + - openapi-types + + stream-replace-string@2.0.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + svgo@4.0.0: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.4.4 + + tiny-inflate@1.0.3: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + tslib@2.8.1: + optional: true + + type-fest@4.41.0: {} + + typescript@5.9.3: {} + + ufo@1.6.3: {} + + ultrahtml@1.6.0: {} + + uncrypto@0.1.3: {} + + unified@11.0.5: + dependencies: + "@types/unist": 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.4: + dependencies: + css-tree: 3.1.0 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + "@types/unist": 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + "@types/unist": 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + "@types/unist": 3.0.3 + array-iterate: 2.0.1 + + unist-util-position-from-estree@2.0.0: + dependencies: + "@types/unist": 3.0.3 + + unist-util-position@5.0.0: + dependencies: + "@types/unist": 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + "@types/unist": 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + "@types/unist": 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + "@types/unist": 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + "@types/unist": 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + "@types/unist": 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.4: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.5 + lru-cache: 11.2.6 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + + url-template@3.1.1: {} + + util-deprecate@1.0.2: {} + + vfile-location@5.0.3: + dependencies: + "@types/unist": 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + "@types/unist": 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + "@types/unist": 3.0.3 + vfile-message: 4.0.3 + + vite@6.4.1: + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + + vitefu@1.1.1(vite@6.4.1): + optionalDependencies: + vite: 6.4.1 + + web-namespaces@2.0.1: {} + + which-pm-runs@1.1.0: {} + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + xxhash-wasm@1.1.0: {} + + yargs-parser@21.1.1: {} + + yocto-queue@1.2.2: {} + + yocto-spinner@0.2.3: + dependencies: + yoctocolors: 2.1.2 + + yoctocolors@2.1.2: {} + + zod-to-json-schema@3.25.1(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): + dependencies: + typescript: 5.9.3 + zod: 3.25.76 + + zod@3.25.76: {} + + zwitch@2.0.4: {} diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico new file mode 100644 index 00000000..9bf9b97a Binary files /dev/null and b/docs/public/favicon.ico differ diff --git a/docs/public/open-graph.jpg b/docs/public/open-graph.jpg new file mode 100644 index 00000000..b2a5f1d2 Binary files /dev/null and b/docs/public/open-graph.jpg differ diff --git a/docs/scripts/i18n-filter.sh b/docs/scripts/i18n-filter.sh new file mode 100755 index 00000000..51b506e8 --- /dev/null +++ b/docs/scripts/i18n-filter.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# This script deletes language files not declared in the .i18n-filter file + +set -e + +# Exit if the directory isn't found +if [ ! -d $1 ] +then + echo "$1 directory does not exist." + exit +fi + +cd $1 + +# Exit if the .i18n-filter isn't found +if [[ -f .i18n-filter ]] +then + # delete all languages not present in .i18n-filter + for i in *; do + if ! grep -qxFe "$i" .i18n-filter; then + echo "Deleting: $i" + + rm -rf "$i" + fi + done +else + echo "$1/.i18n-filter file not found!" + exit +fi diff --git a/docs/setup-development.md b/docs/setup-development.md deleted file mode 100644 index 23721a24..00000000 --- a/docs/setup-development.md +++ /dev/null @@ -1,391 +0,0 @@ -# Setup your development environment - -## Table of contents - -- [Introduction](#introduction) -- [Pre-requisites](#pre-requisites) -- [(recommended) Develop inside the app Container with VSCode](#recommended-develop-inside-the-app-container-with-vscode) -- [(not-recommended) Develop outside the app container](#not-recommended-develop-outside-the-app-container) -- [Install Castopod Host's dependencies](#install-castopod-hosts-dependencies) -- [Initialize and populate database](#initialize-and-populate-database) -- [Start hacking](#start-hacking) -- [Going Further](#going-further) - - [Useful docker / docker-compose commands](#useful-docker--docker-compose-commands) -- [Known issues](#known-issues) - - [Allocation failed - JavaScript heap out of memory](#allocation-failed---javascript-heap-out-of-memory) - - [Files created inside container are attributed to root locally (Linux)](#files-created-inside-container-are-attributed-to-root-locally-linux) - -## Introduction - -Castopod Host is a web app based on the `php` framework -[CodeIgniter 4](https://codeigniter.com). - -To setup a dev environment, we use [Docker](https://www.docker.com/). A -`docker-compose.yml` and `Dockerfile` are included in the project's root folder -to help you kickstart your contribution. - -> Know that you don't need any prior knowledge of Docker to follow the next -> steps. However, if you wish to use your own environment, feel free to do so! - -## Pre-requisites - -0. Install [docker](https://docs.docker.com/get-docker). - -1. Clone Castopod Host project by running: - - ```bash - git clone https://code.podlibre.org/podlibre/castopod-host.git - ``` - -2. Create a `.env` file with the minimum required config to connect the app to - the database and use redis as a cache handler: - - ```ini - CI_ENVIRONMENT="development" - - # By default, this is set to true in the app config. - # For development, this must be set to false as it is - # on a local environment - app.forceGlobalSecureRequests=false - - app.baseURL="http://localhost:8080/" - app.mediaBaseURL="http://localhost:8080/" - - app.adminGateway="cp-admin" - app.authGateway="cp-auth" - - database.default.hostname="mariadb" - database.default.database="castopod" - database.default.username="podlibre" - database.default.password="castopod" - - cache.handler="redis" - cache.redis.host = "redis" - - # You may not want to use redis as your cache handler - # Comment/remove the two lines above and uncomment - # the next line for file caching. - #cache.handler="file" - ``` - - > _NB._ You can tweak your environment by setting more environment variables - > in your custom `.env` file. See the `env` for examples or the - > [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) - > for more info. - -3. (for docker desktop) Add the repository you've cloned to docker desktop's - `Settings` > `Resources` > `File Sharing` - -## (recommended) Develop inside the app Container with VSCode - -If you're working in VSCode, you can take advantage of the `.devcontainer/` -folder. It defines a development environment (dev container) with preinstalled -requirements and VSCode extensions so you don't have to worry about them. All -required services will be loaded automagically! - -1. Install the VSCode extension - [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) -2. `Ctrl/Cmd + Shift + P` > `Open in container` - - > The VSCode window will reload inside the dev container. Expect several - > minutes during first load as it is building all necessary services. - - **Note**: The dev container will start by running Castopod Host's php server. - During development, you will have to start [Vite](https://vitejs.dev)'s dev - server for compiling the typescript code and styles: - - ```bash - # run Vite dev server - npm run dev - ``` - - If there is any issue with the php server not running, you can restart them - using the following commands: - - ```bash - # run Castopod host server - php spark serve --host 0.0.0.0 - ``` - -3. You're all set! 🎉 - - You're now **inside the dev container**, you may use the VSCode console - (`Terminal` > `New Terminal`) to run any command: - - ```bash - # PHP is installed - php -v - - # Composer is installed - composer -V - - # npm is installed - npm -v - - # git is installed - git version - ``` - -For more info, see -[VSCode Remote Containers](https://code.visualstudio.com/docs/remote/containers) - -## (not-recommended) Develop outside the app container - -You do not wish to use the VSCode devcontainer? No problem! - -1. Start docker containers manually: - - Go to project's root folder and run: - - ```bash - # starts all services declared in docker-compose.yml file - # -d option starts the containers in the background - docker-compose up -d - - # See all running processes (you should see 3 processes running) - docker-compose ps - - # Alternatively, you can check all docker processes - docker ps -a - - ``` - - > The `docker-compose up -d` command will boot 4 containers in the - > background: - > - > - `castopod-host_app`: a php based container with CodeIgniter4 requirements - > installed - > - `castopod-host_redis`: a [redis](https://redis.io/) database to handle - > queries and pages caching - > - `castopod-host_mariadb`: a [mariadb](https://mariadb.org/) server for - > persistent data - > - `castopod-host_phpmyadmin`: a phpmyadmin server to visualize the mariadb - > database. - -2. Run any command by prefixing them with `docker-compose run --rm app`: - - ```bash - # use PHP - docker-compose run --rm app php -v - - # use Composer - docker-compose run --rm app composer -V - - # use npm - docker-compose run --rm app npm -v - - # use git - docker-compose run --rm app git version - ``` - -## Install Castopod Host's dependencies - -1. Install php dependencies with [Composer](https://getcomposer.org/) - - ```bash - composer install - ``` - - > **Note:** - > - > The php dependencies aren't included in the repository. Composer will check - > the `composer.json` and `composer.lock` files to download the packages with - > the right versions. The dependencies will live under the `vendor/` folder. - > For more info, check out the - > [Composer documentation](https://getcomposer.org/doc/). - -2. Install javascript dependencies with [npm](https://www.npmjs.com/) - - ```bash - npm install - ``` - - > **Note:** - > - > The javascript dependencies aren't included in the repository. Npm will - > check the `package.json` and `package.lock` files to download the packages - > with the right versions. The dependencies will live under the `node_module` - > folder. For more info, check out the - > [NPM documentation](https://docs.npmjs.com/). - -3. Generate static assets: - - ```bash - # build all assets at once - npm run build:static - - # generate/copy specific assets - npm run build:icons - npm run build:svg - npm run copy:images - ``` - - > **Note:** - > - > The static assets generated live under the `public/assets` folder, it - > includes javascript, styles, images, fonts, icons and svg files. - -## Initialize and populate database - -> **Note:** -> -> You may skip this section if you go through the install wizard (go to -> `/cp-install`). - -1. Build the database with the migrate command: - - ```bash - # loads the database schema during first migration - php spark migrate -all - ``` - - You may need to undo the migration (rollback): - - ```bash - # rolls back database schema (deletes all tables and their content) - php spark migrate:rollback - ``` - -2. Populate the database with the required data: - - ```bash - # Populates all required data - php spark db:seed AppSeeder - ``` - - You may choose to add data separately: - - ```bash - # Populates all categories - php spark db:seed CategorySeeder - - # Populates all Languages - php spark db:seed LanguageSeeder - - # Populates all podcasts platforms - php spark db:seed PlatformSeeder - - # Populates all Authentication data (roles definition…) - php spark db:seed AuthSeeder - ``` - -3. (optionnal) Populate the database with test data: - - ```bash - # Populates test data (login: admin / password: AGUehL3P) - php spark db:seed TestSeeder - - # Populates with fake podcast analytics - php spark db:seed FakePodcastsAnalyticsSeeder - - # Populates with fake website analytics - php spark db:seed FakeWebsiteAnalyticsSeeder - ``` - - TestSeeder will add an active superadmin user with the following credentials: - - - username: **admin** - - password: **AGUehL3P** - -## Start hacking - -You're all set! Start working your magic by updating the project's files! Help -yourself to the -[CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for -more insights. - -To see your changes, go to: - -- [localhost:8080](http://localhost:8080/) for the Castopod Host app -- [localhost:8888](http://localhost:8888/) for the phpmyadmin interface: - - - username: **podlibre** - - password: **castopod** - ---- - -## Going Further - -### Useful docker / docker-compose commands - -```bash -# monitor the app container -docker-compose logs --tail 50 --follow --timestamps app - -# interact with redis server using included redis-cli command -docker exec -it castopod-host_redis redis-cli - -# monitor the redis container -docker-compose logs --tail 50 --follow --timestamps redis - -# monitor the mariadb container -docker-compose logs --tail 50 --follow --timestamps mariadb - -# monitor the phpmyadmin container -docker-compose logs --tail 50 --follow --timestamps phpmyadmin - -# restart docker containers -docker-compose restart - -# Destroy all containers, opposite of `up` command -docker-compose down - -# Rebuild app container -docker-compose build app -``` - -Check [docker](https://docs.docker.com/engine/reference/commandline/docker/) and -[docker-compose](https://docs.docker.com/compose/reference/) documentations for -more insights. - -## Known issues - -### Allocation failed - JavaScript heap out of memory - -This happens when running `npm install`. - -👉 By default, docker might not have access to enough RAM. Allocate more memory -and run `npm install` again. - -### Files created inside container are attributed to root locally (Linux) - -You may use Linux user namespaces to fix this on your machine: - -> **Note:** -> -> Replace "username" with your local username - -1. Go to `/etc/docker/daemon.json` and add: - - ```json - { - "userns-remap": "username" - } - ``` - -2. Configure the subordinate uid/guid: - - ```bash - # in /etc/subuid - username:1000:1 - username:100000:65536 - ``` - - ```bash - # in /etc/subgid - username:1000:1 - username:100000:65536 - ``` - -3. Restart docker: - - ```bash - sudo systemctl restart docker - ``` - -4. That's it! Now, the root user in the container will be mapped to the user on - your local machine, no more permission issues! 🎉 - -You can check -[this great article](https://www.jujens.eu/posts/en/2017/Jul/02/docker-userns-remap/) -to know more about how it works. diff --git a/docs/src/.i18n-filter b/docs/src/.i18n-filter new file mode 100644 index 00000000..9871cee8 --- /dev/null +++ b/docs/src/.i18n-filter @@ -0,0 +1,9 @@ +en +ca +de +es +fr +nn-no +pt-br +sr-latn +zh-hans diff --git a/docs/src/assets/castopod-logo-inline.svg b/docs/src/assets/castopod-logo-inline.svg new file mode 100644 index 00000000..c7300840 --- /dev/null +++ b/docs/src/assets/castopod-logo-inline.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/docs/src/assets/images/sponsors/adaures.svg b/docs/src/assets/images/sponsors/adaures.svg new file mode 100644 index 00000000..aded8d98 --- /dev/null +++ b/docs/src/assets/images/sponsors/adaures.svg @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/docs/src/assets/images/sponsors/nlnet.svg b/docs/src/assets/images/sponsors/nlnet.svg new file mode 100644 index 00000000..5fa21021 --- /dev/null +++ b/docs/src/assets/images/sponsors/nlnet.svg @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/docs/src/components/DocsVersionSelect.astro b/docs/src/components/DocsVersionSelect.astro new file mode 100644 index 00000000..9bedafa9 --- /dev/null +++ b/docs/src/components/DocsVersionSelect.astro @@ -0,0 +1,34 @@ +--- +import Select from '@astrojs/starlight/components/Select.astro'; +--- + + + ' -# honeypot.container = '
    {template}
    ' - -#-------------------------------------------------------------------- -# SECURITY -#-------------------------------------------------------------------- - -# security.tokenName = 'csrf_token_name' -# security.headerName = 'X-CSRF-TOKEN' -# security.cookieName = 'csrf_cookie_name' -# security.expires = 7200 -# security.regenerate = true -# security.redirect = true -# security.samesite = 'Lax' +# session.driver = 'CodeIgniter\Session\Handlers\FileHandler' +# session.savePath = null #-------------------------------------------------------------------- # LOGGER diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..c9d330e6 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,23 @@ +import globals from "globals"; +import eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; +import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; + +export default [ + ...tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.strict, + eslintPluginPrettierRecommended + ), + { + ignores: ["public/*", "docs/*", "vendor/*", "castopod/*"], + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, +]; diff --git a/modules/Admin/Config/Admin.php b/modules/Admin/Config/Admin.php new file mode 100644 index 00000000..56741428 --- /dev/null +++ b/modules/Admin/Config/Admin.php @@ -0,0 +1,24 @@ +add('scheduled-video-clips', 'SchedulerController::generateVideoClips', [ + 'namespace' => 'Modules\Admin\Controllers', +]); + +// Admin area routes +$routes->group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\Admin\Controllers', + ], + static function ($routes): void { + $routes->get('/', 'DashboardController', [ + 'as' => 'admin', + ]); + $routes->group('settings', static function ($routes): void { + $routes->get('/', 'SettingsController', [ + 'as' => 'settings-general', + 'filter' => 'permission:admin.settings', + ]); + $routes->post('instance', 'SettingsController::instanceEditAction', [ + 'as' => 'settings-instance', + 'filter' => 'permission:admin.settings', + ]); + $routes->get('instance-delete-icon', 'SettingsController::deleteIconAction', [ + 'as' => 'settings-instance-delete-icon', + 'filter' => 'permission:admin.settings', + ]); + $routes->post('instance-images-regenerate', 'SettingsController::regenerateImagesAction', [ + 'as' => 'settings-images-regenerate', + 'filter' => 'permission:admin.settings', + ]); + $routes->post('instance-housekeeping-run', 'SettingsController::housekeepingAction', [ + 'as' => 'settings-housekeeping-run', + 'filter' => 'permission:admin.settings', + ]); + $routes->get('theme', 'SettingsController::themeView', [ + 'as' => 'settings-theme', + 'filter' => 'permission:admin.settings', + ]); + $routes->post('theme', 'SettingsController::themeAction', [ + 'as' => 'settings-theme', + 'filter' => 'permission:admin.settings', + ]); + }); + $routes->group('persons', static function ($routes): void { + $routes->get('/', 'PersonController::list', [ + 'as' => 'person-list', + 'filter' => 'permission:persons.manage', + ]); + $routes->get('new', 'PersonController::createView', [ + 'as' => 'person-create', + 'filter' => 'permission:persons.manage', + ]); + $routes->post('new', 'PersonController::createAction', [ + 'filter' => 'permission:persons.manage', + ]); + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'PersonController::view/$1', [ + 'as' => 'person-view', + 'filter' => 'permission:persons.manage', + ]); + $routes->get('edit', 'PersonController::editView/$1', [ + 'as' => 'person-edit', + 'filter' => 'permission:persons.manage', + ]); + $routes->post('edit', 'PersonController::editAction/$1', [ + 'filter' => 'permission:persons.manage', + ]); + $routes->add('delete', 'PersonController::deleteAction/$1', [ + 'as' => 'person-delete', + 'filter' => 'permission:persons.manage', + ]); + }); + }); + // Podcasts + $routes->group('podcasts', static function ($routes): void { + $routes->get('/', 'PodcastController::list', [ + 'as' => 'podcast-list', + ]); + $routes->get('new', 'PodcastController::createView', [ + 'as' => 'podcast-create', + 'filter' => 'permission:podcasts.create', + ]); + $routes->post('new', 'PodcastController::createAction', [ + 'filter' => 'permission:podcasts.create', + ]); + // Podcast + // Use ids in admin area to help permission and group lookups + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'PodcastController::view/$1', [ + 'as' => 'podcast-view', + 'filter' => 'permission:podcast$1.view', + ]); + $routes->get('edit', 'PodcastController::editView/$1', [ + 'as' => 'podcast-edit', + 'filter' => 'permission:podcast$1.edit', + ]); + $routes->post('edit', 'PodcastController::editAction/$1', [ + 'filter' => 'permission:podcast$1.edit', + ]); + $routes->get( + 'publish', + 'PodcastController::publishView/$1', + [ + 'as' => 'podcast-publish', + 'filter' => 'permission:podcast$1.manage-publications', + ], + ); + $routes->post( + 'publish', + 'PodcastController::publishAction/$1', + [ + 'filter' => 'permission:podcast$1.manage-publications', + ], + ); + $routes->get( + 'publish-edit', + 'PodcastController::publishEditView/$1', + [ + 'as' => 'podcast-publish_edit', + 'filter' => 'permission:podcast$1.manage-publications', + ], + ); + $routes->post( + 'publish-edit', + 'PodcastController::publishEditAction/$1', + [ + 'filter' => 'permission:podcast$1.manage-publications', + ], + ); + $routes->get( + 'publish-cancel', + 'PodcastController::publishCancelAction/$1', + [ + 'as' => 'podcast-publish-cancel', + 'filter' => 'permission:podcast$1.manage-publications', + ], + ); + $routes->get('edit/delete-banner', 'PodcastController::deleteBannerAction/$1', [ + 'as' => 'podcast-banner-delete', + 'filter' => 'permission:podcast$1.edit', + ]); + $routes->get('delete', 'PodcastController::deleteView/$1', [ + 'as' => 'podcast-delete', + 'filter' => 'permission:podcast$1.delete', + ]); + $routes->post('delete', 'PodcastController::deleteAction/$1', [ + 'filter' => 'permission:podcast$1.delete', + ]); + $routes->group('persons', static function ($routes): void { + $routes->get('/', 'PodcastPersonController::index/$1', [ + 'as' => 'podcast-persons-manage', + 'filter' => 'permission:podcast$1.manage-persons', + ]); + $routes->post( + '/', + 'PodcastPersonController::createAction/$1', + [ + 'filter' => 'permission:podcast$1.manage-persons', + ], + ); + $routes->get( + '(:num)/remove', + 'PodcastPersonController::deleteAction/$1/$2', + [ + 'as' => 'podcast-person-remove', + 'filter' => 'permission:podcast$1.manage-persons', + ], + ); + }); + $routes->group('analytics', static function ($routes): void { + $routes->get('/', 'PodcastController::analyticsView/$1', [ + 'as' => 'podcast-analytics', + 'filter' => 'permission:podcast$1.view', + ]); + $routes->get( + 'webpages', + 'PodcastController::analyticsWebpagesView/$1', + [ + 'as' => 'podcast-analytics-webpages', + 'filter' => 'permission:podcast$1.view', + ], + ); + $routes->get( + 'locations', + 'PodcastController::analyticsLocationsView/$1', + [ + 'as' => 'podcast-analytics-locations', + 'filter' => 'permission:podcast$1.view', + ], + ); + $routes->get( + 'unique-listeners', + 'PodcastController::analyticsUniqueListenersView/$1', + [ + 'as' => 'podcast-analytics-unique-listeners', + 'filter' => 'permission:podcast$1.view', + ], + ); + $routes->get( + 'listening-time', + 'PodcastController::analyticsListeningTimeView/$1', + [ + 'as' => 'podcast-analytics-listening-time', + 'filter' => 'permission:podcast$1.view', + ], + ); + $routes->get( + 'time-periods', + 'PodcastController::analyticsTimePeriodsView/$1', + [ + 'as' => 'podcast-analytics-time-periods', + 'filter' => 'permission:podcast$1.view', + ], + ); + $routes->get( + 'players', + 'PodcastController::analyticsPlayersView/$1', + [ + 'as' => 'podcast-analytics-players', + 'filter' => 'permission:podcast$1.view', + ], + ); + }); + // Podcast episodes + $routes->group('episodes', static function ($routes): void { + $routes->get('/', 'EpisodeController::list/$1', [ + 'as' => 'episode-list', + 'filter' => 'permission:podcast$1.episodes.view', + ]); + $routes->get('new', 'EpisodeController::createView/$1', [ + 'as' => 'episode-create', + 'filter' => 'permission:podcast$1.episodes.create', + ]); + $routes->post( + 'new', + 'EpisodeController::createAction/$1', + [ + 'filter' => 'permission:podcast$1.episodes.create', + ], + ); + // Episode + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'EpisodeController::view/$1/$2', [ + 'as' => 'episode-view', + 'filter' => 'permission:podcast$1.episodes.view', + ]); + $routes->get('edit', 'EpisodeController::editView/$1/$2', [ + 'as' => 'episode-edit', + 'filter' => 'permission:podcast$1.episodes.edit', + ]); + $routes->post( + 'edit', + 'EpisodeController::editAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.edit', + ], + ); + $routes->get( + 'publish', + 'EpisodeController::publishView/$1/$2', + [ + 'as' => 'episode-publish', + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->post( + 'publish', + 'EpisodeController::publishAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->get( + 'publish-edit', + 'EpisodeController::publishEditView/$1/$2', + [ + 'as' => 'episode-publish_edit', + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->post( + 'publish-edit', + 'EpisodeController::publishEditAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->get( + 'publish-cancel', + 'EpisodeController::publishCancelAction/$1/$2', + [ + 'as' => 'episode-publish-cancel', + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->get( + 'publish-date-edit', + 'EpisodeController::publishDateEditView/$1/$2', + [ + 'as' => 'episode-publish_date_edit', + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->post( + 'publish-date-edit', + 'EpisodeController::publishDateEditAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->get( + 'unpublish', + 'EpisodeController::unpublishView/$1/$2', + [ + 'as' => 'episode-unpublish', + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->post( + 'unpublish', + 'EpisodeController::unpublishAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.manage-publications', + ], + ); + $routes->get( + 'delete', + 'EpisodeController::deleteView/$1/$2', + [ + 'as' => 'episode-delete', + 'filter' => 'permission:podcast$1.episodes.delete', + ], + ); + $routes->post( + 'delete', + 'EpisodeController::deleteAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.delete', + ], + ); + $routes->get( + 'transcript-delete', + 'EpisodeController::transcriptDelete/$1/$2', + [ + 'as' => 'transcript-delete', + 'filter' => 'permission:podcast$1.episodes.edit', + ], + ); + $routes->get( + 'chapters-delete', + 'EpisodeController::chaptersDelete/$1/$2', + [ + 'as' => 'chapters-delete', + 'filter' => 'permission:podcast$1.episodes.edit', + ], + ); + $routes->get( + 'soundbites', + 'SoundbiteController::list/$1/$2', + [ + 'as' => 'soundbites-list', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'soundbites/new', + 'SoundbiteController::createView/$1/$2', + [ + 'as' => 'soundbites-create', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->post( + 'soundbites/new', + 'SoundbiteController::createAction/$1/$2', + [ + 'as' => 'soundbites-create', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'soundbites/(:num)/delete', + 'SoundbiteController::deleteAction/$1/$2/$3', + [ + 'as' => 'soundbites-delete', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'video-clips', + 'VideoClipsController::list/$1/$2', + [ + 'as' => 'video-clips-list', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'video-clips/new', + 'VideoClipsController::createView/$1/$2', + [ + 'as' => 'video-clips-create', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->post( + 'video-clips/new', + 'VideoClipsController::createAction/$1/$2', + [ + 'as' => 'video-clips-create', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'video-clips/(:num)', + 'VideoClipsController::view/$1/$2/$3', + [ + 'as' => 'video-clip', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'video-clips/(:num)/retry', + 'VideoClipsController::retryAction/$1/$2/$3', + [ + 'as' => 'video-clip-retry', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'video-clips/(:num)/delete', + 'VideoClipsController::deleteAction/$1/$2/$3', + [ + 'as' => 'video-clip-delete', + 'filter' => 'permission:podcast$1.episodes.manage-clips', + ], + ); + $routes->get( + 'embed', + 'EpisodeController::embedView/$1/$2', + [ + 'as' => 'embed-add', + 'filter' => 'permission:podcast$1.episodes.edit', + ], + ); + $routes->group('persons', static function ($routes): void { + $routes->get('/', 'EpisodePersonController::index/$1/$2', [ + 'as' => 'episode-persons-manage', + 'filter' => 'permission:podcast$1.episodes.manage-persons', + ]); + $routes->post( + '/', + 'EpisodePersonController::createAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.episodes.manage-persons', + ], + ); + $routes->get( + '(:num)/remove', + 'EpisodePersonController::deleteAction/$1/$2/$3', + [ + 'as' => 'episode-person-remove', + 'filter' => 'permission:podcast$1.episodes.manage-persons', + ], + ); + }); + $routes->group('comments', static function ($routes): void { + $routes->post( + 'new', + 'EpisodeController::commentCreateAction/$1/$2', + [ + 'as' => 'comment-attempt-create', + 'filter' => 'permission:podcast$1.episodes.manage-comments', + ], + ); + $routes->post( + '(:uuid)/reply', + 'EpisodeController::commentReplyAction/$1/$2/$3', + [ + 'as' => 'comment-attempt-reply', + 'filter' => 'permission:podcast$1.episodes.manage-comments', + ], + ); + $routes->post( + 'delete', + 'EpisodeController::commentDeleteAction/$1/$2', + [ + 'as' => 'comment-attempt-delete', + 'filter' => 'permission:podcast$1.episodes.manage-comments', + ], + ); + }); + }); + }); + // Podcast notifications + $routes->group('notifications', static function ($routes): void { + $routes->get('/', 'NotificationController::list/$1', [ + 'as' => 'notification-list', + 'filter' => 'permission:podcast$1.manage-notifications', + ]); + $routes->get('(:num)/mark-as-read', 'NotificationController::markAsReadAction/$1/$2', [ + 'as' => 'notification-mark-as-read', + 'filter' => 'permission:podcast$1.manage-notifications', + ]); + $routes->get('mark-all-as-read', 'NotificationController::markAllAsReadAction/$1', [ + 'as' => 'notification-mark-all-as-read', + 'filter' => 'permission:podcast$1.manage-notifications', + ]); + }); + }); + }); + // Instance wide Fediverse config + $routes->group('fediverse', static function ($routes): void { + $routes->get('/', 'FediverseController::dashboard', [ + 'as' => 'fediverse-dashboard', + ]); + $routes->get( + 'blocked-actors', + 'FediverseController::blockedActorsView', + [ + 'as' => 'fediverse-blocked-actors', + 'filter' => 'permission:fediverse.manage-blocks', + ], + ); + $routes->get( + 'blocked-domains', + 'FediverseController::blockedDomainsView', + [ + 'as' => 'fediverse-blocked-domains', + 'filter' => 'permission:fediverse.manage-blocks', + ], + ); + }); + // Pages + $routes->group('pages', static function ($routes): void { + $routes->get('/', 'PageController::list', [ + 'as' => 'page-list', + 'filter' => 'permission:pages.manage', + ]); + $routes->get('new', 'PageController::createView', [ + 'as' => 'page-create', + 'filter' => 'permission:pages.manage', + ]); + $routes->post('new', 'PageController::createAction', [ + 'filter' => 'permission:pages.manage', + ]); + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'PageController::view/$1', [ + 'as' => 'page-view', + ]); + $routes->get('edit', 'PageController::editView/$1', [ + 'as' => 'page-edit', + 'filter' => 'permission:pages.manage', + ]); + $routes->post('edit', 'PageController::editAction/$1', [ + 'filter' => 'permission:pages.manage', + ]); + $routes->get('delete', 'PageController::deleteAction/$1', [ + 'as' => 'page-delete', + 'filter' => 'permission:pages.manage', + ]); + }); + }); + + $routes->get('about', 'AboutController', [ + 'as' => 'admin-about', + 'filter' => 'permission:admin.settings', + ]); + + $routes->post('update', 'AboutController::updateAction', [ + 'as' => 'update', + 'filter' => 'permission:admin.settings', + ]); + }, +); diff --git a/modules/Admin/Controllers/AboutController.php b/modules/Admin/Controllers/AboutController.php new file mode 100644 index 00000000..b61abf29 --- /dev/null +++ b/modules/Admin/Controllers/AboutController.php @@ -0,0 +1,53 @@ + current_domain(), + 'version' => CP_VERSION, + 'php_version' => PHP_VERSION, + 'os' => PHP_OS, + 'languages' => implode(', ', config('App')->supportedLocales), + ]; + + $this->setHtmlHead(lang('AboutCastopod.title')); + return view('settings/about', [ + 'info' => $instanceInfo, + ]); + } + + public function updateAction(): RedirectResponse + { + if ($this->request->getPost('action') === 'database') { + return $this->migrateDatabase(); + } + + return redirect()->back() + ->with('error', lang('Security.disallowedAction')); + } + + public function migrateDatabase(): RedirectResponse + { + $migrate = service('migrations'); + + $migrate->setNamespace(null) + ->latest(); + + return redirect()->back() + ->with('message', lang('AboutCastopod.messages.databaseUpdateSuccess')); + } +} diff --git a/modules/Admin/Controllers/BaseController.php b/modules/Admin/Controllers/BaseController.php new file mode 100644 index 00000000..1dc5d3bc --- /dev/null +++ b/modules/Admin/Controllers/BaseController.php @@ -0,0 +1,64 @@ +helpers = [...$this->helpers, 'auth', 'breadcrumb', 'svg', 'components', 'misc']; + + // Do Not Edit This Line + parent::initController($request, $response, $logger); + + Theme::setTheme('admin'); + } + + protected function setHtmlHead(string $title): void + { + /** @var HtmlHead $head */ + $head = service('html_head'); + + $head + ->title($title . ' | Castopod Admin') + ->description( + 'Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.', + ); + } +} diff --git a/modules/Admin/Controllers/DashboardController.php b/modules/Admin/Controllers/DashboardController.php new file mode 100644 index 00000000..725412a3 --- /dev/null +++ b/modules/Admin/Controllers/DashboardController.php @@ -0,0 +1,93 @@ +builder() + ->countAll(); + $podcastsLastPublishedAt = new PodcastModel() + ->builder() + ->selectMax('published_at', 'last_published_at') + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray()[0]['last_published_at']; + $podcastsData['number_of_podcasts'] = (int) $podcastsCount; + $podcastsData['last_published_at'] = $podcastsLastPublishedAt === null ? null : new Time( + $podcastsLastPublishedAt, + ); + + $episodesData = []; + $episodesCount = new EpisodeModel() + ->builder() + ->countAll(); + $episodesLastPublishedAt = new EpisodeModel() + ->builder() + ->selectMax('published_at', 'last_published_at') + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray()[0]['last_published_at']; + $episodesData['number_of_episodes'] = (int) $episodesCount; + $episodesData['last_published_at'] = $episodesLastPublishedAt === null ? null : new Time( + $episodesLastPublishedAt, + ); + + $totalUploaded = new MediaModel() + ->builder() + ->selectSum('file_size') + ->get() + ->getResultArray()[0]; + + $appStorageLimit = config('App') + ->storageLimit; + if ($appStorageLimit === null || $appStorageLimit < 0) { + $storageLimitBytes = disk_total_space('./'); + } else { + $storageLimitBytes = $appStorageLimit * 1000000000; + } + + $storageData = [ + 'limit' => formatBytes((int) $storageLimitBytes), + 'percentage' => round((((int) $totalUploaded['file_size']) / $storageLimitBytes) * 100, 0), + 'total_uploaded' => formatBytes((int) $totalUploaded['file_size']), + ]; + + $onlyPodcastId = null; + if ($podcastsData['number_of_podcasts'] === 1) { + $onlyPodcastId = new PodcastModel() + ->first() + ->id; + } + + $bandwidthLimit = config('App') + ->bandwidthLimit; + + $data = [ + 'podcastsData' => $podcastsData, + 'episodesData' => $episodesData, + 'storageData' => $storageData, + 'bandwidthLimit' => $bandwidthLimit === null ? null : formatBytes($bandwidthLimit * 1000000000), + 'onlyPodcastId' => $onlyPodcastId, + ]; + + $this->setHtmlHead(lang('Dashboard.home')); + return view('dashboard', $data); + } +} diff --git a/modules/Admin/Controllers/EpisodeController.php b/modules/Admin/Controllers/EpisodeController.php new file mode 100644 index 00000000..7319afd6 --- /dev/null +++ b/modules/Admin/Controllers/EpisodeController.php @@ -0,0 +1,1013 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->{$method}($podcast); + } + + if ( + ! ($episode = new EpisodeModel()->getEpisodeById((int) $params[1])) instanceof Episode + ) { + throw PageNotFoundException::forPageNotFound(); + } + + unset($params[0]); + unset($params[1]); + + return $this->{$method}($episode, ...$params); + } + + public function list(Podcast $podcast): string + { + /** @var ?string $query */ + $query = $this->request->getGet('q'); + + $episodeModel = new EpisodeModel(); + if ($query !== null && $query !== '') { + // Default value for MySQL Full-Text Search's minimum length of words is 4. + // Use LIKE operator as a fallback. + if (strlen($query) < 4) { + $episodes = $episodeModel + ->where('podcast_id', $podcast->id) + ->like('title', $episodeModel->db->escapeLikeString($query)) + ->orLike('description_markdown', $episodeModel->db->escapeLikeString($query)) + ->orLike('slug', $episodeModel->db->escapeLikeString($query)) + ->orLike('location_name', $episodeModel->db->escapeLikeString($query)) + ->orderBy('-`published_at`', '', false) + ->orderBy('created_at', 'desc'); + } else { + $episodes = $episodeModel + ->where('podcast_id', $podcast->id) + ->where( + "MATCH (title, description_markdown, slug, location_name) AGAINST ('{$episodeModel->db->escapeString( + $query, + )}')", + ); + } + } else { + $episodes = $episodeModel + ->where('podcast_id', $podcast->id) + ->orderBy('-`published_at`', '', false) + ->orderBy('created_at', 'desc'); + } + + helper('form'); + $data = [ + 'podcast' => $podcast, + 'episodes' => $episodes->paginate(10), + 'pager' => $episodes->pager, + 'query' => $query, + ]; + + $this->setHtmlHead(lang('Episode.all_podcast_episodes')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('episode/list', $data); + } + + public function view(Episode $episode): string + { + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead($episode->title); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/view', $data); + } + + public function createView(Podcast $podcast): string + { + helper(['form']); + + $currentSeasonNumber = new EpisodeModel() + ->getCurrentSeasonNumber($podcast->id); + $data = [ + 'podcast' => $podcast, + 'currentSeasonNumber' => $currentSeasonNumber, + 'nextEpisodeNumber' => new EpisodeModel() + ->getNextEpisodeNumber($podcast->id, $currentSeasonNumber), + ]; + + $this->setHtmlHead(lang('Episode.create')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('episode/create', $data); + } + + public function createAction(Podcast $podcast): RedirectResponse + { + $rules = [ + 'title' => 'required', + 'slug' => 'required|max_length[128]', + 'audio_file' => 'uploaded[audio_file]|ext_in[audio_file,mp3,m4a]', + 'cover' => 'is_image[cover]|ext_in[cover,jpg,jpeg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]', + 'transcript_file' => 'ext_in[transcript_file,srt,vtt]', + 'chapters_file' => 'ext_in[chapters_file,json]|is_json[chapters_file]', + ]; + + if ($podcast->type === 'serial' && $this->request->getPost('type') === 'full') { + $rules['episode_number'] = 'required'; + } + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + if (new EpisodeModel() + ->where([ + 'slug' => $validData['slug'], + 'podcast_id' => $podcast->id, + ]) + ->first() instanceof Episode) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.messages.sameSlugError')); + } + + $newEpisode = new Episode([ + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'podcast_id' => $podcast->id, + 'title' => $this->request->getPost('title'), + 'slug' => $this->request->getPost('slug'), + 'guid' => null, + 'audio' => $this->request->getFile('audio_file'), + 'cover' => $this->request->getFile('cover'), + 'description_markdown' => $this->request->getPost('description'), + 'location' => $this->request->getPost('location_name') === '' ? null : new Location( + $this->request->getPost('location_name'), + ), + 'transcript' => $this->request->getFile('transcript'), + 'chapters' => $this->request->getFile('chapters'), + 'parental_advisory' => $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null, + 'number' => $this->request->getPost('episode_number') + ? (int) $this->request->getPost('episode_number') + : null, + 'season_number' => $this->request->getPost('season_number') + ? (int) $this->request->getPost('season_number') + : null, + 'type' => $this->request->getPost('type'), + 'is_blocked' => $this->request->getPost('block') === 'yes', + 'is_premium' => $this->request->getPost('premium') === 'yes', + 'published_at' => null, + ]); + + $transcriptChoice = $this->request->getPost('transcript-choice'); + if ($transcriptChoice === 'upload-file') { + $newEpisode->setTranscript($this->request->getFile('transcript_file')); + } elseif ($transcriptChoice === 'remote-url') { + $newEpisode->transcript_remote_url = $this->request->getPost( + 'transcript_remote_url', + ) === '' ? null : $this->request->getPost('transcript_remote_url'); + } + + $chaptersChoice = $this->request->getPost('chapters-choice'); + if ($chaptersChoice === 'upload-file') { + $newEpisode->setChapters($this->request->getFile('chapters_file')); + } elseif ($chaptersChoice === 'remote-url') { + $newEpisode->chapters_remote_url = $this->request->getPost( + 'chapters_remote_url', + ) === '' ? null : $this->request->getPost('chapters_remote_url'); + } + + $episodeModel = new EpisodeModel(); + if (! ($newEpisodeId = $episodeModel->insert($newEpisode, true))) { + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + return redirect()->route('episode-view', [$podcast->id, $newEpisodeId])->with( + 'message', + lang('Episode.messages.createSuccess'), + ); + } + + public function editView(Episode $episode): string + { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Episode.edit')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/edit', $data); + } + + public function editAction(Episode $episode): RedirectResponse + { + $rules = [ + 'title' => 'required', + 'slug' => 'required|max_length[128]', + 'audio_file' => 'ext_in[audio_file,mp3,m4a]', + 'cover' => 'is_image[cover]|ext_in[cover,jpg,jpeg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]', + 'transcript_file' => 'ext_in[transcript_file,srt,vtt]', + 'chapters_file' => 'ext_in[chapters_file,json]|is_json[chapters_file]', + ]; + + if ($episode->podcast->type === 'serial' && $this->request->getPost('type') === 'full') { + $rules['episode_number'] = 'required'; + } + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $episode->title = $this->request->getPost('title'); + $episode->slug = $validData['slug']; + $episode->description_markdown = $this->request->getPost('description'); + $episode->location = $this->request->getPost('location_name') === '' ? null : new Location( + $this->request->getPost('location_name'), + ); + $episode->parental_advisory = + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null; + $episode->number = $this->request->getPost('episode_number') ?: null; + $episode->season_number = $this->request->getPost('season_number') ?: null; + $episode->type = $this->request->getPost('type'); + $episode->is_blocked = $this->request->getPost('block') === 'yes'; + $episode->is_premium = $this->request->getPost('premium') === 'yes'; + + $episode->updated_by = (int) user_id(); + $episode->setAudio($this->request->getFile('audio_file')); + $episode->setCover($this->request->getFile('cover')); + + // republish on websub hubs upon edit + $episode->is_published_on_hubs = false; + + $transcriptChoice = $this->request->getPost('transcript-choice'); + if ($transcriptChoice === 'upload-file') { + $transcriptFile = $this->request->getFile('transcript_file'); + if ($transcriptFile instanceof UploadedFile && $transcriptFile->isValid()) { + $episode->setTranscript($transcriptFile); + $episode->transcript_remote_url = null; + } + } elseif ($transcriptChoice === 'remote-url') { + if ( + ($transcriptRemoteUrl = $this->request->getPost('transcript_remote_url')) && + (($transcriptFile = $episode->transcript_id) !== null) + ) { + new MediaModel() + ->deleteMedia($episode->transcript); + } + + $episode->transcript_remote_url = $transcriptRemoteUrl === '' ? null : $transcriptRemoteUrl; + } + + $chaptersChoice = $this->request->getPost('chapters-choice'); + if ($chaptersChoice === 'upload-file') { + $chaptersFile = $this->request->getFile('chapters_file'); + if ($chaptersFile instanceof UploadedFile && $chaptersFile->isValid()) { + $episode->setChapters($chaptersFile); + $episode->chapters_remote_url = null; + } + } elseif ($chaptersChoice === 'remote-url') { + if ( + ($chaptersRemoteUrl = $this->request->getPost('chapters_remote_url')) && + (($chaptersFile = $episode->chapters) instanceof Chapters) + ) { + new MediaModel() + ->deleteMedia($episode->chapters); + } + + $episode->chapters_remote_url = $chaptersRemoteUrl === '' ? null : $chaptersRemoteUrl; + } + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + return redirect()->route('episode-edit', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Episode.messages.editSuccess'), + ); + } + + public function transcriptDelete(Episode $episode): RedirectResponse + { + if (! $episode->transcript instanceof Transcript) { + return redirect()->back(); + } + + $mediaModel = new MediaModel(); + if (! $mediaModel->deleteMedia($episode->transcript)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $mediaModel->errors()); + } + + return redirect()->back(); + } + + public function chaptersDelete(Episode $episode): RedirectResponse + { + if (! $episode->chapters instanceof Chapters) { + return redirect()->back(); + } + + $mediaModel = new MediaModel(); + if (! $mediaModel->deleteMedia($episode->chapters)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $mediaModel->errors()); + } + + return redirect()->back(); + } + + public function publishView(Episode $episode): string | RedirectResponse + { + if ($episode->publication_status === 'not_published') { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Episode.publish')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/publish', $data); + } + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'error', + lang('Episode.publish_error'), + ); + } + + public function publishAction(Episode $episode): RedirectResponse + { + if ($episode->podcast->publication_status === 'published') { + $rules = [ + 'publication_method' => 'required', + 'scheduled_publication_date' => 'valid_date[Y-m-d H:i]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + } + + $db = db_connect(); + $db->transStart(); + + $newPost = new Post([ + 'actor_id' => $episode->podcast->actor_id, + 'episode_id' => $episode->id, + 'message' => $this->request->getPost('message'), + 'created_by' => user_id(), + ]); + + if ($episode->podcast->publication_status === 'published') { + $publishMethod = $this->request->getPost('publication_method'); + if ($publishMethod === 'schedule') { + $scheduledPublicationDate = $this->request->getPost('scheduled_publication_date'); + if ($scheduledPublicationDate) { + $episode->published_at = Time::createFromFormat( + 'Y-m-d H:i', + $scheduledPublicationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } else { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.messages.scheduleDateError')); + } + } else { + $episode->published_at = Time::now(); + } + } elseif ($episode->podcast->publication_status === 'scheduled') { + // podcast publication date has already been set + $episode->published_at = $episode->podcast->published_at->addSeconds(1); + } else { + $episode->published_at = Time::now(); + } + + $newPost->published_at = $episode->published_at; + + $postModel = new PostModel(); + if (! $postModel->addPost($newPost)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Episode.messages.publishSuccess', [ + 'publication_status' => $episode->publication_status, + ]), + ); + } + + public function publishEditView(Episode $episode): string | RedirectResponse + { + if (in_array($episode->publication_status, ['scheduled', 'with_podcast'], true)) { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + 'post' => new PostModel() + ->where([ + 'actor_id' => $episode->podcast->actor_id, + 'episode_id' => $episode->id, + ]) + ->first(), + ]; + + $this->setHtmlHead(lang('Episode.publish_edit')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/publish_edit', $data); + } + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'error', + lang('Episode.publish_edit_error'), + ); + } + + public function publishEditAction(Episode $episode): RedirectResponse + { + if ($episode->podcast->publication_status === 'published') { + $rules = [ + 'post_id' => 'required', + 'publication_method' => 'required', + 'scheduled_publication_date' => 'valid_date[Y-m-d H:i]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + } + + $db = db_connect(); + $db->transStart(); + + if ($episode->podcast->publication_status === 'published') { + $publishMethod = $this->request->getPost('publication_method'); + if ($publishMethod === 'schedule') { + $scheduledPublicationDate = $this->request->getPost('scheduled_publication_date'); + if ($scheduledPublicationDate) { + $episode->published_at = Time::createFromFormat( + 'Y-m-d H:i', + $scheduledPublicationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } else { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.messages.scheduleDateError')); + } + } else { + $episode->published_at = Time::now(); + } + } elseif ($episode->podcast->publication_status === 'scheduled') { + // podcast publication date has already been set + $episode->published_at = $episode->podcast->published_at->addSeconds(1); + } else { + $episode->published_at = Time::now(); + } + + $post = new PostModel() + ->getPostById($this->request->getPost('post_id')); + + if ($post instanceof Post) { + $post->message = $this->request->getPost('message'); + $post->published_at = $episode->published_at; + + $postModel = new PostModel(); + if (! $postModel->editPost($post)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Episode.messages.publishSuccess', [ + 'publication_status' => $episode->publication_status, + ]), + ); + } + + public function publishCancelAction(Episode $episode): RedirectResponse + { + if (in_array($episode->publication_status, ['scheduled', 'with_podcast'], true)) { + $db = db_connect(); + $db->transStart(); + + $postModel = new PostModel(); + $post = $postModel + ->where([ + 'actor_id' => $episode->podcast->actor_id, + 'episode_id' => $episode->id, + ]) + ->first(); + $postModel->removePost($post); + + $episode->published_at = null; + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Episode.messages.publishCancelSuccess'), + ); + } + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id]); + } + + public function publishDateEditView(Episode $episode): string|RedirectResponse + { + // only accessible if episode is already published + if ($episode->publication_status !== 'published') { + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'error', + lang('Episode.publish_date_edit_error'), + ); + } + + helper('form'); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Episode.publish_date_edit')); + replace_breadcrumb_params([ + 0 => $episode->podcast->title, + 1 => $episode->title, + ]); + return view('episode/publish_date_edit', $data); + } + + /** + * Allows to set an episode's publication date to a past date + * + * Prevents setting a future date as it does not make sense to set a future published date to an already published + * episode. This also prevents any side-effects from occurring. + */ + public function publishDateEditAction(Episode $episode): RedirectResponse + { + $rules = [ + 'new_publication_date' => 'valid_date[Y-m-d H:i]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newPublicationDate = $validData['new_publication_date']; + + $newPublicationDate = Time::createFromFormat( + 'Y-m-d H:i', + $newPublicationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + + if ($newPublicationDate->isAfter(Time::now())) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.publish_date_edit_future_error')); + } + + $episode->published_at = $newPublicationDate; + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Episode.publish_date_edit_success'), + ); + } + + public function unpublishView(Episode $episode): string | RedirectResponse + { + if ($episode->publication_status !== 'published') { + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id])->with( + 'error', + lang('Episode.unpublish_error'), + ); + } + + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Episode.unpublish')); + replace_breadcrumb_params([ + 0 => $episode->podcast->title, + 1 => $episode->title, + ]); + return view('episode/unpublish', $data); + } + + public function unpublishAction(Episode $episode): RedirectResponse + { + $rules = [ + 'understand' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $db = db_connect(); + + $db->transStart(); + + $allPostsLinkedToEpisode = new PostModel() + ->where([ + 'episode_id' => $episode->id, + 'in_reply_to_id' => null, + 'reblog_of_id' => null, + ]) + ->findAll(); + foreach ($allPostsLinkedToEpisode as $post) { + new PostModel() + ->removePost($post); + } + + $allCommentsLinkedToEpisode = new EpisodeCommentModel() + ->where([ + 'episode_id' => $episode->id, + 'in_reply_to_id' => null, + ]) + ->findAll(); + foreach ($allCommentsLinkedToEpisode as $comment) { + new EpisodeCommentModel() + ->removeComment($comment); + } + + // set episode published_at to null to unpublish + $episode->published_at = null; + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + // set podcast is_published_on_hubs to false to trigger websub push + new PodcastModel() + ->update($episode->podcast_id, [ + 'is_published_on_hubs' => 0, + ]); + + $db->transComplete(); + + return redirect()->route('episode-view', [$episode->podcast_id, $episode->id]); + } + + public function deleteView(Episode $episode): string + { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Episode.delete')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/delete', $data); + } + + public function deleteAction(Episode $episode): RedirectResponse + { + $rules = [ + 'understand' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + if ($episode->published_at instanceof Time) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.messages.deletePublishedEpisodeError')); + } + + $db = db_connect(); + + $db->transStart(); + + $episodeModel = new EpisodeModel(); + + if (! $episodeModel->delete($episode->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $episodeMediaList = [$episode->transcript, $episode->chapters, $episode->audio]; + + //only delete episode cover if different from podcast's + if ($episode->cover_id !== null) { + $episodeMediaList[] = $episode->cover; + } + + $mediaModel = new MediaModel(); + + //delete episode media records from database + foreach ($episodeMediaList as $episodeMedia) { + if ($episodeMedia !== null && ! $mediaModel->delete($episodeMedia->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Episode.messages.deleteError', [ + 'type' => $episodeMedia->type, + ])); + } + } + + $db->transComplete(); + + $warnings = []; + + //remove episode media files from disk + foreach ($episodeMediaList as $episodeMedia) { + if ($episodeMedia === null) { + continue; + } + + if ($episodeMedia->deleteFile()) { + continue; + } + + $warnings[] = lang('Episode.messages.deleteFileError', [ + 'type' => $episodeMedia->type, + 'file_key' => $episodeMedia->file_key, + ]); + } + + if ($warnings !== []) { + return redirect() + ->route('episode-list', [$episode->podcast_id]) + ->with('message', lang('Episode.messages.deleteSuccess')) + ->with('warnings', $warnings); + } + + return redirect()->route('episode-list', [$episode->podcast_id])->with( + 'message', + lang('Episode.messages.deleteSuccess'), + ); + } + + public function embedView(Episode $episode): string + { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + 'themes' => EpisodeModel::$themes, + ]; + + $this->setHtmlHead(lang('Episode.embed.title')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/embed', $data); + } + + public function commentCreateAction(Episode $episode): RedirectResponse + { + $rules = [ + 'message' => 'required|max_length[500]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newComment = new EpisodeComment([ + 'actor_id' => interact_as_actor_id(), + 'episode_id' => $episode->id, + 'message' => $validData['message'], + 'created_at' => new Time('now'), + 'created_by' => user_id(), + ]); + + $commentModel = new EpisodeCommentModel(); + if ( + ! $commentModel->addComment($newComment, true) + ) { + return redirect() + ->back() + ->withInput() + ->with('errors', $commentModel->errors()); + } + + // Comment has been successfully created + return redirect()->back(); + } + + public function commentReplyAction(Episode $episode, string $commentId): RedirectResponse + { + $rules = [ + 'message' => 'required|max_length[500]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newReply = new EpisodeComment([ + 'actor_id' => interact_as_actor_id(), + 'episode_id' => $episode->id, + 'message' => $validData['message'], + 'in_reply_to_id' => $commentId, + 'created_at' => new Time('now'), + 'created_by' => user_id(), + ]); + + $commentModel = new EpisodeCommentModel(); + if ( + ! $commentModel->addComment($newReply, true) + ) { + return redirect() + ->back() + ->withInput() + ->with('errors', $commentModel->errors()); + } + + // Reply has been successfully created + return redirect()->back(); + } +} diff --git a/modules/Admin/Controllers/EpisodePersonController.php b/modules/Admin/Controllers/EpisodePersonController.php new file mode 100644 index 00000000..dd8c8e4a --- /dev/null +++ b/modules/Admin/Controllers/EpisodePersonController.php @@ -0,0 +1,103 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->{$method}($podcast); + } + + if ( + ! ($episode = new EpisodeModel()->getEpisodeById((int) $params[1])) instanceof Episode + ) { + throw PageNotFoundException::forPageNotFound(); + } + + unset($params[0]); + unset($params[1]); + + return $this->{$method}($episode, ...$params); + } + + public function index(Episode $episode): string + { + helper('form'); + + $data = [ + 'episode' => $episode, + 'podcast' => $episode->podcast, + 'personOptions' => new PersonModel() + ->getPersonOptions(), + 'taxonomyOptions' => new PersonModel() + ->getTaxonomyOptions(), + ]; + + $this->setHtmlHead(lang('Person.episode_form.title')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/persons', $data); + } + + public function createAction(Episode $episode): RedirectResponse + { + $rules = [ + 'persons' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + new PersonModel() + ->addEpisodePersons( + $episode->podcast_id, + $episode->id, + $validData['persons'], + $this->request->getPost('roles') ?? [], + ); + + return redirect()->back(); + } + + public function deleteAction(Episode $episode, string $personId): RedirectResponse + { + new PersonModel() + ->removePersonFromEpisode($episode->podcast_id, $episode->id, (int) $personId); + + return redirect()->back(); + } +} diff --git a/modules/Admin/Controllers/FediverseController.php b/modules/Admin/Controllers/FediverseController.php new file mode 100644 index 00000000..55b9ffcd --- /dev/null +++ b/modules/Admin/Controllers/FediverseController.php @@ -0,0 +1,47 @@ +route('fediverse-blocked-actors'); + } + + public function blockedActorsView(): string + { + helper(['form']); + + $blockedActors = model('ActorModel', false) + ->getBlockedActors(); + + $this->setHtmlHead(lang('Fediverse.blocked_actors')); + return view('fediverse/blocked_actors', [ + 'blockedActors' => $blockedActors, + ]); + } + + public function blockedDomainsView(): string + { + helper(['form']); + + $blockedDomains = model('BlockedDomainModel', false) + ->getBlockedDomains(); + + $this->setHtmlHead(lang('Fediverse.blocked_domains')); + return view('fediverse/blocked_domains', [ + 'blockedDomains' => $blockedDomains, + ]); + } +} diff --git a/modules/Admin/Controllers/NotificationController.php b/modules/Admin/Controllers/NotificationController.php new file mode 100644 index 00000000..06f0cea1 --- /dev/null +++ b/modules/Admin/Controllers/NotificationController.php @@ -0,0 +1,105 @@ +getPodcastById((int) $params[0])) instanceof Podcast + ) { + throw PageNotFoundException::forPageNotFound(); + } + + $params[0] = $podcast; + + if (count($params) > 1) { + if ( + ! ($notification = new NotificationModel()->find($params[1])) instanceof Notification + ) { + throw PageNotFoundException::forPageNotFound(); + } + + $params[1] = $notification; + } + + return $this->{$method}(...$params); + } + + public function list(Podcast $podcast): string + { + $notifications = new NotificationModel() + ->where('target_actor_id', $podcast->actor_id) + ->orderBy('created_at', 'desc'); + + $data = [ + 'podcast' => $podcast, + 'notifications' => $notifications->paginate(10), + 'pager' => $notifications->pager, + ]; + + $this->setHtmlHead(lang('Notifications.title')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/notifications', $data); + } + + public function markAllAsReadAction(Podcast $podcast): RedirectResponse + { + $notifications = new NotificationModel() + ->where('target_actor_id', $podcast->actor_id) + ->where('read_at') + ->findAll(); + + foreach ($notifications as $notification) { + $notification->read_at = new Time('now'); + new NotificationModel() + ->update($notification->id, $notification); + } + + return redirect()->back(); + } + + public function markAsReadAction(Podcast $podcast, Notification $notification): RedirectResponse + { + $notification->read_at = new Time('now'); + $notificationModel = new NotificationModel(); + $notificationModel->update($notification->id, $notification); + + if ($notification->post_id === null) { + return redirect()->route('podcast-activity', [esc($podcast->handle)]); + } + + $post = new PostModel() + ->getPostById($notification->post_id); + + return redirect()->route('post', [$podcast->handle, $post->id]); + } +} diff --git a/modules/Admin/Controllers/PageController.php b/modules/Admin/Controllers/PageController.php new file mode 100644 index 00000000..8c406463 --- /dev/null +++ b/modules/Admin/Controllers/PageController.php @@ -0,0 +1,122 @@ +{$method}(); + } + + if (($page = new PageModel()->find($params[0])) instanceof Page) { + return $this->{$method}($page); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function list(): string + { + $this->setHtmlHead(lang('Page.all_pages')); + $data = [ + 'pages' => new PageModel() + ->findAll(), + ]; + + return view('page/list', $data); + } + + public function view(Page $page): string + { + $this->setHtmlHead($page->title); + return view('page/view', [ + 'page' => $page, + ]); + } + + public function createView(): string + { + helper('form'); + + $this->setHtmlHead(lang('Page.create')); + return view('page/create'); + } + + public function createAction(): RedirectResponse + { + $page = new Page([ + 'title' => $this->request->getPost('title'), + 'slug' => $this->request->getPost('slug'), + 'content_markdown' => $this->request->getPost('content'), + ]); + + $pageModel = new PageModel(); + + if (! $pageModel->insert($page)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $pageModel->errors()); + } + + return redirect() + ->route('page-list') + ->with('message', lang('Page.messages.createSuccess', [ + 'pageTitle' => $page->title, + ])); + } + + public function editView(Page $page): string + { + helper('form'); + + $this->setHtmlHead(lang('Page.edit')); + replace_breadcrumb_params([ + 0 => $page->title, + ]); + return view('page/edit', [ + 'page' => $page, + ]); + } + + public function editAction(Page $page): RedirectResponse + { + $page->title = $this->request->getPost('title'); + $page->slug = $this->request->getPost('slug'); + $page->content_markdown = $this->request->getPost('content'); + + $pageModel = new PageModel(); + + if (! $pageModel->update($page->id, $page)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $pageModel->errors()); + } + + return redirect()->route('page-edit', [$page->id])->with('message', lang('Page.messages.editSuccess')); + } + + public function deleteAction(Page $page): RedirectResponse + { + new PageModel() + ->delete($page->id); + + return redirect()->route('page-list'); + } +} diff --git a/modules/Admin/Controllers/PersonController.php b/modules/Admin/Controllers/PersonController.php new file mode 100644 index 00000000..95bc4a28 --- /dev/null +++ b/modules/Admin/Controllers/PersonController.php @@ -0,0 +1,171 @@ +{$method}(); + } + + if ( + ($person = new PersonModel()->getPersonById((int) $params[0])) instanceof Person + ) { + return $this->{$method}($person); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function list(): string + { + $data = [ + 'persons' => new PersonModel() + ->orderBy('full_name') + ->findAll(), + ]; + + $this->setHtmlHead(lang('Person.all_persons')); + return view('person/list', $data); + } + + public function view(Person $person): string + { + $data = [ + 'person' => $person, + ]; + + $this->setHtmlHead($person->full_name); + replace_breadcrumb_params([ + 0 => $person->full_name, + ]); + return view('person/view', $data); + } + + public function createView(): string + { + helper(['form']); + + $this->setHtmlHead(lang('Person.create')); + return view('person/create'); + } + + public function createAction(): RedirectResponse + { + $rules = [ + 'avatar' => 'is_image[avatar]|ext_in[avatar,jpg,jpeg,png]|min_dims[avatar,400,400]|is_image_ratio[avatar,1,1]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $db = db_connect(); + $db->transStart(); + + $person = new Person([ + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'full_name' => $this->request->getPost('full_name'), + 'unique_name' => $this->request->getPost('unique_name'), + 'information_url' => $this->request->getPost('information_url'), + 'avatar' => $this->request->getFile('avatar'), + ]); + + $personModel = new PersonModel(); + if (! $personModel->insert($person)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $personModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('person-list') + ->with('message', lang('Person.messages.createSuccess')); + } + + public function editView(Person $person): string + { + helper('form'); + + $data = [ + 'person' => $person, + ]; + + $this->setHtmlHead(lang('Person.edit')); + replace_breadcrumb_params([ + 0 => $person->full_name, + ]); + return view('person/edit', $data); + } + + public function editAction(Person $person): RedirectResponse + { + $rules = [ + 'avatar' => 'is_image[avatar]|ext_in[avatar,jpg,jpeg,png]|min_dims[avatar,400,400]|is_image_ratio[avatar,1,1]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $person->updated_by = user_id(); + $person->full_name = $this->request->getPost('full_name'); + $person->unique_name = $this->request->getPost('unique_name'); + $person->information_url = $this->request->getPost('information_url'); + $person->setAvatar($this->request->getFile('avatar')); + + $personModel = new PersonModel(); + if (! $personModel->update($person->id, $person)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $personModel->errors()); + } + + return redirect()->route('person-edit', [$person->id])->with( + 'message', + lang('Person.messages.editSuccess'), + ); + } + + public function deleteAction(Person $person): RedirectResponse + { + if ($person->avatar_id !== null) { + // delete avatar to prevent collision if recreating person + new MediaModel() + ->deleteMedia($person->avatar); + } + + new PersonModel() + ->delete($person->id); + + return redirect()->route('person-list') + ->with('message', lang('Person.messages.deleteSuccess')); + } +} diff --git a/modules/Admin/Controllers/PodcastController.php b/modules/Admin/Controllers/PodcastController.php new file mode 100644 index 00000000..96204b66 --- /dev/null +++ b/modules/Admin/Controllers/PodcastController.php @@ -0,0 +1,956 @@ +{$method}(); + } + + if ( + ($podcast = new PodcastModel()->getPodcastById((int) $params[0])) instanceof Podcast + ) { + return $this->{$method}($podcast); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function list(): string + { + if (auth()->user()->can('podcasts.view')) { + $data = [ + 'podcasts' => new PodcastModel() + ->findAll(), + ]; + } else { + $data = [ + 'podcasts' => get_user_podcasts(auth()->user()), + ]; + } + + $this->setHtmlHead(lang('Podcast.all_podcasts')); + return view('podcast/list', $data); + } + + public function view(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/view', $data); + } + + public function analyticsView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/index', $data); + } + + public function analyticsWebpagesView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/webpages', $data); + } + + public function analyticsLocationsView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/locations', $data); + } + + public function analyticsUniqueListenersView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/unique_listeners', $data); + } + + public function analyticsListeningTimeView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/listening_time', $data); + } + + public function analyticsTimePeriodsView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/time_periods', $data); + } + + public function analyticsPlayersView(Podcast $podcast): string + { + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead($podcast->title); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/analytics/players', $data); + } + + public function createView(): string + { + helper(['form', 'misc']); + + $languageOptions = new LanguageModel() + ->getLanguageOptions(); + $categoryOptions = new CategoryModel() + ->getCategoryOptions(); + + $data = [ + 'languageOptions' => $languageOptions, + 'categoryOptions' => $categoryOptions, + 'browserLang' => get_browser_language($this->request->getServer('HTTP_ACCEPT_LANGUAGE')), + ]; + + $this->setHtmlHead(lang('Podcast.create')); + return view('podcast/create', $data); + } + + public function createAction(): RedirectResponse + { + $rules = [ + 'cover' => 'uploaded[cover]|is_image[cover]|ext_in[cover,jpg,jpeg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]', + 'banner' => 'is_image[banner]|ext_in[banner,jpg,jpeg,png]|min_dims[banner,1500,500]|is_image_ratio[banner,3,1]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $db = db_connect(); + $db->transStart(); + + $newPodcast = new Podcast([ + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'title' => $this->request->getPost('title'), + 'handle' => $this->request->getPost('handle'), + 'cover' => $this->request->getFile('cover'), + 'banner' => $this->request->getFile('banner'), + 'description_markdown' => $this->request->getPost('description'), + 'language_code' => $this->request->getPost('language'), + 'category_id' => $this->request->getPost('category'), + 'parental_advisory' => $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null, + 'owner_name' => $this->request->getPost('owner_name'), + 'owner_email' => $this->request->getPost('owner_email'), + 'publisher' => $this->request->getPost('publisher'), + 'type' => $this->request->getPost('type'), + 'copyright' => $this->request->getPost('copyright'), + 'location' => $this->request->getPost('location_name') === '' ? null : new Location( + $this->request->getPost('location_name'), + ), + 'is_blocked' => $this->request->getPost('block') === 'yes', + 'is_completed' => $this->request->getPost('complete') === 'yes', + 'is_locked' => $this->request->getPost('lock') === 'yes', + 'is_premium_by_default' => $this->request->getPost('premium_by_default') === 'yes', + 'published_at' => null, + ]); + + $podcastModel = new PodcastModel(); + if (! ($newPodcastId = $podcastModel->insert($newPodcast, true))) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + // generate podcast roles and permissions + // before setting current user as podcast admin + config('AuthGroups') + ->generatePodcastAuthorizations($newPodcastId); + add_podcast_group(auth()->user(), (int) $newPodcastId, setting('AuthGroups.mostPowerfulPodcastGroup')); + + // set Podcast categories + new CategoryModel() + ->setPodcastCategories((int) $newPodcastId, $this->request->getPost('other_categories') ?? []); + + $db->transComplete(); + + return redirect()->route('podcast-view', [$newPodcastId])->with( + 'message', + lang('Podcast.messages.createSuccess'), + ); + } + + public function editView(Podcast $podcast): string + { + helper('form'); + + $languageOptions = new LanguageModel() + ->getLanguageOptions(); + $categoryOptions = new CategoryModel() + ->getCategoryOptions(); + + $data = [ + 'podcast' => $podcast, + 'languageOptions' => $languageOptions, + 'categoryOptions' => $categoryOptions, + ]; + + $this->setHtmlHead(lang('Podcast.edit')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/edit', $data); + } + + public function editAction(Podcast $podcast): RedirectResponse + { + $rules = [ + 'cover' => 'is_image[cover]|ext_in[cover,jpg,jpeg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]', + 'banner' => 'is_image[banner]|ext_in[banner,jpg,jpeg,png]|min_dims[banner,1500,500]|is_image_ratio[banner,3,1]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $podcast->updated_by = (int) user_id(); + + $podcast->title = $this->request->getPost('title'); + $podcast->description_markdown = $this->request->getPost('description'); + $podcast->setCover($this->request->getFile('cover')); + $podcast->setBanner($this->request->getFile('banner')); + + $podcast->language_code = $this->request->getPost('language'); + $podcast->category_id = $this->request->getPost('category'); + $podcast->parental_advisory = + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null; + $podcast->publisher = $this->request->getPost('publisher'); + $podcast->owner_name = $this->request->getPost('owner_name'); + $podcast->owner_email = $this->request->getPost('owner_email'); + $podcast->type = $this->request->getPost('type'); + $podcast->copyright = $this->request->getPost('copyright'); + $podcast->location = $this->request->getPost('location_name') === '' ? null : new Location( + $this->request->getPost('location_name'), + ); + $podcast->new_feed_url = $this->request->getPost('new_feed_url') === '' ? null : $this->request->getPost( + 'new_feed_url', + ); + + $podcast->is_blocked = $this->request->getPost('block') === 'yes'; + $podcast->is_completed = + $this->request->getPost('complete') === 'yes'; + $podcast->is_locked = $this->request->getPost('lock') === 'yes'; + $podcast->is_premium_by_default = $this->request->getPost('premium_by_default') === 'yes'; + + // republish on websub hubs upon edit + $podcast->is_published_on_hubs = false; + + $db = db_connect(); + + $db->transStart(); + + $podcastModel = new PodcastModel(); + if (! $podcastModel->update($podcast->id, $podcast)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + // set Podcast categories + new CategoryModel() + ->setPodcastCategories($podcast->id, $this->request->getPost('other_categories') ?? []); + + // New feed url redirect + service('settings') + ->set( + 'Podcast.redirect_to_new_feed', + $this->request->getPost('redirect_to_new_feed') === 'yes', + 'podcast:' . $podcast->id, + ); + + $db->transComplete(); + + return redirect()->route('podcast-edit', [$podcast->id])->with( + 'message', + lang('Podcast.messages.editSuccess'), + ); + } + + public function deleteBannerAction(Podcast $podcast): RedirectResponse + { + if (! $podcast->banner instanceof Image) { + return redirect()->back(); + } + + $db = db_connect(); + + $db->transStart(); + + $mediaModel = new MediaModel(); + if (! $mediaModel->deleteMedia($podcast->banner)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $mediaModel->errors()); + } + + new PodcastModel() + ->clearCache([ + 'id' => $podcast->id, + ]); + + // remove banner url from actor + $actor = new ActorModel() + ->getActorById($podcast->actor_id); + + if ($actor instanceof Actor) { + $actor->cover_image_url = null; + $actor->cover_image_mimetype = null; + + new ActorModel() + ->update($actor->id, $actor); + } + + $db->transComplete(); + + return redirect()->back(); + } + + public function latestEpisodesView(int $limit, int $podcastId): string + { + $episodes = new EpisodeModel() + ->where('podcast_id', $podcastId) + ->orderBy('-`published_at`', '', false) + ->orderBy('created_at', 'desc') + ->findAll($limit); + + return view('podcast/latest_episodes', [ + 'episodes' => $episodes, + 'podcast' => new PodcastModel() + ->getPodcastById($podcastId), + ]); + } + + public function deleteView(Podcast $podcast): string + { + helper(['form']); + + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead(lang('Podcast.delete')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/delete', $data); + } + + public function deleteAction(Podcast $podcast): RedirectResponse + { + $rules = [ + 'understand' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $db = db_connect(); + + $db->transStart(); + + //delete podcast episodes + $podcastEpisodes = new EpisodeModel() + ->where('podcast_id', $podcast->id) + ->findAll(); + + foreach ($podcastEpisodes as $podcastEpisode) { + $episodeModel = new EpisodeModel(); + + if (! $episodeModel->delete($podcastEpisode->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $episodeMediaList = [$podcastEpisode->transcript, $podcastEpisode->chapters, $podcastEpisode->audio]; + + //only delete episode cover if different from podcast's + if ($podcastEpisode->cover_id !== null) { + $episodeMediaList[] = $podcastEpisode->cover; + } + + $mediaModel = new MediaModel(); + + foreach ($episodeMediaList as $episodeMedia) { + if ($episodeMedia !== null && ! $mediaModel->delete($episodeMedia->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Podcast.messages.deleteEpisodeMediaError', [ + 'episode_slug' => $podcastEpisode->slug, + 'type' => $episodeMedia->type, + ])); + } + } + } + + //delete podcast + $podcastModel = new PodcastModel(); + + if (! $podcastModel->delete($podcast->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + //delete podcast media + $podcastMediaList = [ + [ + 'type' => 'cover', + 'file' => $podcast->cover, + ], + ]; + + if ($podcast->banner_id !== null) { + $podcastMediaList[] = + [ + 'type' => 'banner', + 'file' => $podcast->banner, + ]; + } + + $mediaModel = new MediaModel(); + + foreach ($podcastMediaList as $podcastMedia) { + if ($podcastMedia['file'] instanceof Image && ! $mediaModel->delete($podcastMedia['file']->id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Podcast.messages.deletePodcastMediaError', [ + 'type' => $podcastMedia['type'], + ])); + } + } + + //delete podcast actor + $actorModel = new ActorModel(); + + if (! $actorModel->delete($podcast->actor_id)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $actorModel->errors()); + } + + //delete podcast analytics + $analyticsModels = [ + new AnalyticsPodcastModel(), + new AnalyticsPodcastByCountryModel(), + new AnalyticsPodcastByEpisodeModel(), + new AnalyticsPodcastByHourModel(), + new AnalyticsPodcastByPlayerModel(), + new AnalyticsPodcastByRegionModel(), + new AnalyticsWebsiteByBrowserModel(), + new AnalyticsWebsiteByEntryPageModel(), + new AnalyticsWebsiteByRefererModel(), + ]; + foreach ($analyticsModels as $analyticsModel) { + if (! $analyticsModel->where([ + 'podcast_id' => $podcast->id, + ])->delete()) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $analyticsModel->errors()); + } + } + + $db->transComplete(); + + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + //delete podcast media files and folder + $folder = 'podcasts/' . $podcast->handle; + if (! $fileManager->deleteAll($folder)) { + return redirect()->route('podcast-list') + ->with('message', lang('Podcast.messages.deleteSuccess', [ + 'podcast_handle' => $podcast->handle, + ])) + ->with('warning', lang('Podcast.messages.deletePodcastMediaFolderError', [ + 'folder_path' => $folder, + ])); + } + + return redirect()->route('podcast-list') + ->with('message', lang('Podcast.messages.deleteSuccess', [ + 'podcast_handle' => $podcast->handle, + ])); + } + + public function publishView(Podcast $podcast): string | RedirectResponse + { + helper(['form']); + + $data = [ + 'podcast' => $podcast, + ]; + + $this->setHtmlHead(lang('Podcast.publish')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/publish', $data); + } + + public function publishAction(Podcast $podcast): RedirectResponse + { + if ($podcast->publication_status !== 'not_published') { + return redirect()->route('podcast-view', [$podcast->id])->with( + 'error', + lang('Podcast.messages.publishError'), + ); + } + + $rules = [ + 'publication_method' => 'required', + 'scheduled_publication_date' => 'valid_date[Y-m-d H:i]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $db = db_connect(); + $db->transStart(); + + $publishMethod = $validData['publication_method']; + if ($publishMethod === 'schedule') { + $scheduledPublicationDate = $validData['scheduled_publication_date']; + if ($scheduledPublicationDate) { + $podcast->published_at = Time::createFromFormat( + 'Y-m-d H:i', + $scheduledPublicationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } else { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Podcast.messages.scheduleDateError')); + } + } else { + $podcast->published_at = Time::now(); + } + + $message = $this->request->getPost('message'); + // only create post if message is not empty + if ($message !== '') { + $newPost = new Post([ + 'actor_id' => $podcast->actor_id, + 'message' => $message, + 'created_by' => user_id(), + ]); + + $newPost->published_at = $podcast->published_at; + + $postModel = new PostModel(); + if (! $postModel->addPost($newPost)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } + + $episodes = new EpisodeModel() + ->where('podcast_id', $podcast->id) + ->where('published_at !=') + ->findAll(); + + foreach ($episodes as $episode) { + $episode->published_at = $podcast->published_at->addSeconds(1); + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $post = new PostModel() + ->where('episode_id', $episode->id) + ->first(); + + if ($post instanceof Post) { + $post->published_at = $episode->published_at; + $postModel = new PostModel(); + if (! $postModel->update($post->id, $post)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } + } + + $podcastModel = new PodcastModel(); + if (! $podcastModel->update($podcast->id, $podcast)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('podcast-view', [$podcast->id]); + } + + public function publishEditView(Podcast $podcast): string | RedirectResponse + { + helper(['form']); + + $data = [ + 'podcast' => $podcast, + 'post' => new PostModel() + ->where([ + 'actor_id' => $podcast->actor_id, + 'episode_id' => null, + ]) + ->first(), + ]; + + $this->setHtmlHead(lang('Podcast.publish_edit')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/publish_edit', $data); + } + + public function publishEditAction(Podcast $podcast): RedirectResponse + { + if ($podcast->publication_status !== 'scheduled') { + return redirect()->route('podcast-view', [$podcast->id])->with( + 'error', + lang('Podcast.messages.publishEditError'), + ); + } + + $rules = [ + 'publication_method' => 'required', + 'scheduled_publication_date' => 'valid_date[Y-m-d H:i]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $db = db_connect(); + $db->transStart(); + + $publishMethod = $validData['publication_method']; + if ($publishMethod === 'schedule') { + $scheduledPublicationDate = $validData['scheduled_publication_date']; + if ($scheduledPublicationDate) { + $podcast->published_at = Time::createFromFormat( + 'Y-m-d H:i', + $scheduledPublicationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } else { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('error', lang('Podcast.messages.scheduleDateError')); + } + } else { + $podcast->published_at = Time::now(); + } + + $post = new PostModel() + ->where([ + 'actor_id' => $podcast->actor_id, + 'episode_id' => null, + ]) + ->first(); + + $newPostMessage = $this->request->getPost('message'); + + if ($post instanceof Post) { + if ($newPostMessage !== '') { + // edit post if post exists and message is not empty + $post->message = $newPostMessage; + $post->published_at = $podcast->published_at; + + $postModel = new PostModel(); + if (! $postModel->editPost($post)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } else { + // remove post if post exists and message is empty + $postModel = new PostModel(); + $post = $postModel + ->where([ + 'actor_id' => $podcast->actor_id, + 'episode_id' => null, + ]) + ->first(); + $postModel->removePost($post); + } + } elseif ($newPostMessage !== '') { + // create post if there is no post and message is not empty + $newPost = new Post([ + 'actor_id' => $podcast->actor_id, + 'message' => $newPostMessage, + 'created_by' => user_id(), + ]); + + $newPost->published_at = $podcast->published_at; + + $postModel = new PostModel(); + if (! $postModel->addPost($newPost)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } + + $episodes = new EpisodeModel() + ->where('podcast_id', $podcast->id) + ->where('published_at !=') + ->findAll(); + + foreach ($episodes as $episode) { + $episode->published_at = $podcast->published_at->addSeconds(1); + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $post = new PostModel() + ->where('episode_id', $episode->id) + ->first(); + + if ($post instanceof Post) { + $post->published_at = $episode->published_at; + $postModel = new PostModel(); + if (! $postModel->update($post->id, $post)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $postModel->errors()); + } + } + } + + $podcastModel = new PodcastModel(); + if (! $podcastModel->update($podcast->id, $podcast)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('podcast-view', [$podcast->id]); + } + + public function publishCancelAction(Podcast $podcast): RedirectResponse + { + if ($podcast->publication_status !== 'scheduled') { + return redirect()->route('podcast-view', [$podcast->id]); + } + + $db = db_connect(); + $db->transStart(); + + $postModel = new PostModel(); + $post = $postModel + ->where([ + 'actor_id' => $podcast->actor_id, + 'episode_id' => null, + ]) + ->first(); + if ($post instanceof Post) { + $postModel->removePost($post); + } + + $episodes = new EpisodeModel() + ->where('podcast_id', $podcast->id) + ->where('published_at !=') + ->findAll(); + + foreach ($episodes as $episode) { + $episode->published_at = null; + + $episodeModel = new EpisodeModel(); + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $episodeModel->errors()); + } + + $postModel = new PostModel(); + $post = $postModel->where('episode_id', $episode->id) + ->first(); + $postModel->removePost($post); + } + + $podcast->published_at = null; + + $podcastModel = new PodcastModel(); + if (! $podcastModel->update($podcast->id, $podcast)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + + $db->transComplete(); + + return redirect()->route('podcast-view', [$podcast->id])->with( + 'message', + lang('Podcast.messages.publishCancelSuccess'), + ); + } +} diff --git a/modules/Admin/Controllers/PodcastPersonController.php b/modules/Admin/Controllers/PodcastPersonController.php new file mode 100644 index 00000000..7713bbfc --- /dev/null +++ b/modules/Admin/Controllers/PodcastPersonController.php @@ -0,0 +1,88 @@ +getPodcastById((int) $params[0])) instanceof Podcast + ) { + unset($params[0]); + return $this->{$method}($podcast, ...$params); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function index(Podcast $podcast): string + { + helper('form'); + + $data = [ + 'podcast' => $podcast, + 'podcastPersons' => new PersonModel() + ->getPodcastPersons($podcast->id), + 'personOptions' => new PersonModel() + ->getPersonOptions(), + 'taxonomyOptions' => new PersonModel() + ->getTaxonomyOptions(), + ]; + + $this->setHtmlHead(lang('Person.podcast_form.title')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('podcast/persons', $data); + } + + public function createAction(Podcast $podcast): RedirectResponse + { + $rules = [ + 'persons' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + new PersonModel() + ->addPodcastPersons($podcast->id, $validData['persons'], $this->request->getPost('roles') ?? []); + + return redirect()->back(); + } + + public function deleteAction(Podcast $podcast, string $personId): RedirectResponse + { + new PersonModel() + ->removePersonFromPodcast($podcast->id, (int) $personId); + + return redirect()->back(); + } +} diff --git a/modules/Admin/Controllers/SettingsController.php b/modules/Admin/Controllers/SettingsController.php new file mode 100644 index 00000000..f0e8c508 --- /dev/null +++ b/modules/Admin/Controllers/SettingsController.php @@ -0,0 +1,235 @@ +setHtmlHead(lang('Settings.title')); + return view('settings/general'); + } + + public function instanceEditAction(): RedirectResponse + { + $rules = [ + 'site_icon' => 'is_image[site_icon]|ext_in[site_icon,png,jpeg]|is_image_ratio[site_icon,1,1]|min_dims[image,512,512]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $siteName = $this->request->getPost('site_name'); + if ($siteName !== service('settings')->get('App.siteName')) { + service('settings')->set('App.siteName', $siteName); + } + + $siteDescription = $this->request->getPost('site_description'); + if ($siteDescription !== service('settings')->get('App.siteDescription')) { + service('settings')->set('App.siteDescription', $siteDescription); + } + + $siteIconFile = $this->request->getFile('site_icon'); + if ($siteIconFile instanceof UploadedFile && $siteIconFile->isValid()) { + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + // delete site folder in media before repopulating it + $fileManager->deleteAll('site'); + + // convert jpeg image to png if not + if ($siteIconFile->getClientMimeType() !== 'image/png') { + $tempFilePath = tempnam(WRITEPATH . 'temp', 'img_'); + service('image') + ->withFile($siteIconFile->getRealPath()) + ->convert(IMAGETYPE_JPEG) + ->save($tempFilePath); + + @unlink($siteIconFile->getRealPath()); + + $siteIconFile = new File($tempFilePath, true); + } + + $icoTempFilePath = WRITEPATH . 'temp/img_favicon.ico'; + + // generate ico + $ico_lib = new PHP_ICO(); + $ico_lib->add_image($siteIconFile->getRealPath(), [[32, 32], [64, 64]]); + $ico_lib->save_ico($icoTempFilePath); + + // generate random hash to use as a suffix to renew browser cache + $randomHash = substr(bin2hex(random_bytes(18)), 0, 8); + + // save ico + $fileManager->save(new File($icoTempFilePath, true), "site/favicon.{$randomHash}.ico"); + + // resize original to needed sizes + foreach ([64, 180, 192, 512] as $size) { + $tempFilePath = tempnam(WRITEPATH . 'temp', 'img_'); + service('image') + ->withFile($siteIconFile->getRealPath()) + ->resize($size, $size) + ->save($tempFilePath); + + // save sizes to + $fileManager->save(new File($tempFilePath), "site/icon-{$size}.{$randomHash}.png"); + } + + // save original as png + $fileManager->save($siteIconFile, 'site/icon.png'); + + service('settings') + ->set('App.siteIcon', [ + 'ico' => "site/favicon.{$randomHash}.ico", + '64' => "site/icon-64.{$randomHash}.png", + '180' => "site/icon-180.{$randomHash}.png", + '192' => "site/icon-192.{$randomHash}.png", + '512' => "site/icon-512.{$randomHash}.png", + ]); + } + + return redirect('settings-general')->with('message', lang('Settings.instance.editSuccess')); + } + + public function deleteIconAction(): RedirectResponse + { + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + // delete site folder + $fileManager->deleteAll('site'); + + service('settings') + ->forget('App.siteIcon'); + + return redirect('settings-general')->with('message', lang('Settings.instance.deleteIconSuccess')); + } + + public function regenerateImagesAction(): RedirectResponse + { + /** @var Podcast[] $allPodcasts */ + $allPodcasts = new PodcastModel() + ->findAll(); + + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + foreach ($allPodcasts as $podcast) { + $fileManager->deletePodcastImageSizes($podcast->handle); + + $podcast->cover->saveSizes(); + if ($podcast->banner_id !== null) { + $podcast->banner->saveSizes(); + } + + foreach ($podcast->episodes as $episode) { + if ($episode->cover_id !== null) { + $episode->cover->saveSizes(); + } + } + } + + $fileManager->deletePersonImagesSizes(); + + $persons = new PersonModel() + ->findAll(); + foreach ($persons as $person) { + if ($person->avatar_id !== null) { + $person->avatar->saveSizes(); + } + } + + return redirect('settings-general')->with('message', lang('Settings.images.regenerationSuccess')); + } + + public function housekeepingAction(): RedirectResponse + { + if ($this->request->getPost('reset_counts') === 'yes') { + // recalculate fediverse counts + new ActorModel() + ->resetFollowersCount(); + new ActorModel() + ->resetPostsCount(); + new PostModel() + ->setEpisodeIdForRepliesOfEpisodePosts(); + new PostModel() + ->resetFavouritesCount(); + new PostModel() + ->resetReblogsCount(); + new PostModel() + ->resetRepliesCount(); + new EpisodeModel() + ->resetCommentsCount(); + new EpisodeModel() + ->resetPostsCount(); + new EpisodeCommentModel() + ->resetLikesCount(); + new EpisodeCommentModel() + ->resetRepliesCount(); + } + + if ($this->request->getPost('clear_cache') === 'yes') { + cache()->clean(); + } + + if ($this->request->getPost('rename_episodes_files') === 'yes') { + /** @var Audio[] $allAudio */ + $allAudio = new MediaModel('audio') + ->getAllOfType(); + + foreach ($allAudio as $audio) { + $audio->rename(); + } + } + + return redirect('settings-general')->with('message', lang('Settings.housekeeping.runSuccess')); + } + + public function themeView(): string + { + helper('form'); + $this->setHtmlHead(lang('Settings.theme.title')); + return view('settings/theme'); + } + + public function themeAction(): RedirectResponse + { + $theme = $this->request->getPost('theme'); + service('settings') + ->set('App.theme', $theme); + + // delete all pages cache + cache() + ->deleteMatching('page*'); + + return redirect('settings-theme')->with('message', lang('Settings.theme.setInstanceThemeSuccess')); + } +} diff --git a/modules/Admin/Controllers/SoundbiteController.php b/modules/Admin/Controllers/SoundbiteController.php new file mode 100644 index 00000000..2ca68bac --- /dev/null +++ b/modules/Admin/Controllers/SoundbiteController.php @@ -0,0 +1,170 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->{$method}($podcast); + } + + if ( + ! ($episode = new EpisodeModel()->getEpisodeById((int) $params[1])) instanceof Episode + ) { + throw PageNotFoundException::forPageNotFound(); + } + + unset($params[0]); + unset($params[1]); + + return $this->{$method}($episode, ...$params); + } + + public function list(Episode $episode): string + { + $soundbitesBuilder = new ClipModel('audio') + ->where([ + 'podcast_id' => $episode->podcast_id, + 'episode_id' => $episode->id, + 'type' => 'audio', + ]) + ->orderBy('created_at', 'desc'); + + $soundbites = $soundbitesBuilder->paginate(10); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + 'soundbites' => $soundbites, + 'pager' => $soundbitesBuilder->pager, + ]; + + $this->setHtmlHead(lang('Soundbite.list.title')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/soundbites_list', $data); + } + + public function createView(Episode $episode): string + { + helper(['form']); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + $this->setHtmlHead(lang('Soundbite.form.title')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/soundbites_new', $data); + } + + public function createAction(Episode $episode): RedirectResponse + { + $rules = [ + 'title' => 'required', + 'start_time' => 'required|greater_than_equal_to[0]', + 'duration' => 'required|greater_than[0]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newSoundbite = new Soundbite([ + 'title' => $validData['title'], + 'start_time' => (float) $validData['start_time'], + 'duration' => (float) $validData['duration'], + 'type' => 'audio', + 'status' => '', + 'podcast_id' => $episode->podcast_id, + 'episode_id' => $episode->id, + 'created_by' => user_id(), + 'updated_by' => user_id(), + ]); + + $clipModel = new ClipModel('audio'); + if (! $clipModel->save($newSoundbite)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $clipModel->errors()); + } + + return redirect()->route('soundbites-list', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Soundbite.messages.createSuccess'), + ); + } + + public function deleteAction(Episode $episode, string $soundbiteId): RedirectResponse + { + $soundbite = new ClipModel() + ->getSoundbiteById((int) $soundbiteId); + + if (! $soundbite instanceof Soundbite) { + throw PageNotFoundException::forPageNotFound(); + } + + if ($soundbite->media === null) { + // delete Clip directly + new ClipModel() + ->deleteSoundbite($episode->podcast_id, $episode->id, $soundbite->id); + } else { + new ClipModel() + ->clearSoundbiteCache($episode->podcast_id, $episode->id, $soundbite->id); + + $mediaModel = new MediaModel(); + // delete the soundbite file, the clip will be deleted on cascade + if (! $mediaModel->deleteMedia($soundbite->media)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $mediaModel->errors()); + } + } + + return redirect()->route('soundbites-list', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('Soundbite.messages.deleteSuccess'), + ); + } +} diff --git a/modules/Admin/Controllers/VideoClipsController.php b/modules/Admin/Controllers/VideoClipsController.php new file mode 100644 index 00000000..b91305ca --- /dev/null +++ b/modules/Admin/Controllers/VideoClipsController.php @@ -0,0 +1,247 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->{$method}($podcast); + } + + if ( + ! ($episode = new EpisodeModel()->getEpisodeById((int) $params[1])) instanceof Episode + ) { + throw PageNotFoundException::forPageNotFound(); + } + + unset($params[0]); + unset($params[1]); + + return $this->{$method}($episode, ...$params); + } + + public function list(Episode $episode): string + { + $videoClipsBuilder = new ClipModel('video') + ->where([ + 'podcast_id' => $episode->podcast_id, + 'episode_id' => $episode->id, + 'type' => 'video', + ]) + ->orderBy('created_at', 'desc'); + + /** @var BaseClip[] $clips */ + $clips = $videoClipsBuilder->paginate(10); + + $videoClips = []; + foreach ($clips as $clip) { + $videoClips[] = new VideoClip($clip->toArray()); + } + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + 'videoClips' => $videoClips, + 'pager' => $videoClipsBuilder->pager, + ]; + + $this->setHtmlHead(lang('VideoClip.list.title')); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + return view('episode/video_clips_list', $data); + } + + public function view(Episode $episode, string $videoClipId): string + { + $videoClip = new ClipModel() + ->getVideoClipById((int) $videoClipId); + + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + 'videoClip' => $videoClip, + ]; + + $this->setHtmlHead(lang('VideoClip.title', [ + 'videoClipLabel' => esc($videoClip->title), + ])); + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + 2 => $videoClip->title, + ]); + return view('episode/video_clip', $data); + } + + public function createView(Episode $episode): string + { + $data = [ + 'podcast' => $episode->podcast, + 'episode' => $episode, + ]; + + replace_breadcrumb_params([ + 0 => $episode->podcast->at_handle, + 1 => $episode->title, + ]); + + // First, check that requirements to create a video clip are met + $ffmpeg = shell_exec('which ffmpeg'); + $checks = [ + 'ffmpeg' => $ffmpeg !== null, + 'gd' => extension_loaded('gd'), + 'freetype' => extension_loaded('gd') && gd_info()['FreeType Support'], + 'transcript' => $episode->transcript instanceof Transcript, + ]; + + $this->setHtmlHead(lang('VideoClip.form.title')); + + if (array_any($checks, fn (bool $value): bool => ! $value)) { + $data['checks'] = $checks; + return view('episode/video_clips_requirements', $data); + } + + helper('form'); + return view('episode/video_clips_new', $data); + } + + public function createAction(Episode $episode): RedirectResponse + { + $rules = [ + 'title' => 'required', + 'start_time' => 'required|greater_than_equal_to[0]', + 'duration' => 'required|greater_than[0]', + 'format' => 'required|in_list[' . implode(',', array_keys(config('MediaClipper')->formats)) . ']', + 'theme' => 'required|in_list[' . implode(',', array_keys(config('Colors')->themes)) . ']', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $themeName = $validData['theme']; + $themeColors = config('MediaClipper') + ->themes[$themeName]; + $theme = [ + 'name' => $themeName, + 'preview' => $themeColors['preview'], + ]; + + $videoClip = new VideoClip([ + 'title' => $validData['title'], + 'start_time' => (float) $validData['start_time'], + 'duration' => (float) $validData['duration'], + 'theme' => $theme, + 'format' => $validData['format'], + 'type' => 'video', + 'status' => 'queued', + 'podcast_id' => $episode->podcast_id, + 'episode_id' => $episode->id, + 'created_by' => user_id(), + 'updated_by' => user_id(), + ]); + + // Check if video clip exists before inserting a new line + if (new ClipModel()->doesVideoClipExist($videoClip)) { + // video clip already exists + return redirect() + ->back() + ->withInput() + ->with('error', lang('VideoClip.messages.alreadyExistingError')); + } + + new ClipModel() + ->insert($videoClip); + + return redirect()->route('video-clips-list', [$episode->podcast_id, $episode->id])->with( + 'message', + lang('VideoClip.messages.addToQueueSuccess'), + ); + } + + public function retryAction(Episode $episode, string $videoClipId): RedirectResponse + { + $videoClip = new ClipModel() + ->getVideoClipById((int) $videoClipId); + + if (! $videoClip instanceof VideoClip) { + throw PageNotFoundException::forPageNotFound(); + } + + new ClipModel() + ->update($videoClip->id, [ + 'status' => 'queued', + 'job_started_at' => null, + 'job_ended_at' => null, + ]); + + return redirect()->back(); + } + + public function deleteAction(Episode $episode, string $videoClipId): RedirectResponse + { + $videoClip = new ClipModel() + ->getVideoClipById((int) $videoClipId); + + if (! $videoClip instanceof VideoClip) { + throw PageNotFoundException::forPageNotFound(); + } + + if ($videoClip->media === null) { + // delete Clip directly + new ClipModel() + ->deleteVideoClip($videoClip->id); + } else { + new ClipModel() + ->clearVideoClipCache($videoClip->id); + + $mediaModel = new MediaModel(); + // delete the videoClip file, the clip will be deleted on cascade + if (! $mediaModel->deleteMedia($videoClip->media)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $mediaModel->errors()); + } + } + + return redirect()->back(); + } +} diff --git a/modules/Admin/Language/.gitkeep b/modules/Admin/Language/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/modules/Admin/Language/.rsync-filter b/modules/Admin/Language/.rsync-filter new file mode 100644 index 00000000..b802a93d --- /dev/null +++ b/modules/Admin/Language/.rsync-filter @@ -0,0 +1,12 @@ ++ en/*** ++ fr/*** ++ pl/*** ++ de/*** ++ pt-br/*** ++ nn-no/*** ++ es/*** ++ zh-hans/*** ++ ca/*** ++ br/*** ++ sr-latn/*** +- ** diff --git a/modules/Admin/Language/ar/AboutCastopod.php b/modules/Admin/Language/ar/AboutCastopod.php new file mode 100644 index 00000000..f5bc662b --- /dev/null +++ b/modules/Admin/Language/ar/AboutCastopod.php @@ -0,0 +1,22 @@ + 'حول كاستوبود', + 'host_name' => 'إسم المضيف', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'نظام التشغيل', + 'languages' => 'اللغات', + 'update_database' => 'تحديث قاعدة البيانات', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/ar/Breadcrumb.php b/modules/Admin/Language/ar/Breadcrumb.php new file mode 100644 index 00000000..251d9788 --- /dev/null +++ b/modules/Admin/Language/ar/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'الرئيسية', + 'podcasts' => 'بودكاستات', + 'episodes' => 'حلقات', + 'subscriptions' => 'subscriptions', + 'contributors' => 'مساهمون', + 'pages' => 'صفحات', + 'settings' => 'الإعدادات', + 'theme' => 'الحلة', + 'about' => 'about', + 'add' => 'إضافة', + 'new' => 'جديد', + 'edit' => 'تعديل', + 'persons' => 'أشخاص', + 'publish' => 'نشر', + 'publish-edit' => 'تعديل المنشور', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'احذف', + 'remove' => 'remove', + 'fediverse' => 'الفديفرس', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'مستخدمون', + 'my-account' => 'حسابي', + 'change-password' => 'تغيير الكلمة السرية', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'منصات', + 'social' => 'شبكات التواصل الاجتماعي', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'صفحات ويب', + 'unique-listeners' => 'مستمعون فريدون', + 'players' => 'players', + 'listening-time' => 'وقت الاستماع', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'الإشعارات', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/ar/Charts.php b/modules/Admin/Language/ar/Charts.php new file mode 100644 index 00000000..525085f0 --- /dev/null +++ b/modules/Admin/Language/ar/Charts.php @@ -0,0 +1,41 @@ + 'تنزيلات الحلقة حسب الخدمة (للأسبوع الماضي)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'المستمعون الفريدون يوميا', + 'unique_monthly_listeners' => 'المستمعون الفريدون شهريا', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'تنزيلات الحلقة حسب البلد (في الأسبوع الماضي)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'التخزين الشهري (بالميغابايت)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/ar/Common.php b/modules/Admin/Language/ar/Common.php new file mode 100644 index 00000000..fc39a83b --- /dev/null +++ b/modules/Admin/Language/ar/Common.php @@ -0,0 +1,52 @@ + 'نعم', + 'no' => 'لا', + 'cancel' => 'ألغِ', + 'optional' => 'اختياري', + 'more' => 'المزيد', + 'no_data' => 'لم يتم العثور على بيانات!', + 'close' => 'أغلق', + 'edit' => 'تعديل', + 'copy' => 'انسخ', + 'copied' => 'تم نسخه!', + 'home' => 'الرئيسية', + 'explicit' => 'Explicit', + 'powered_by' => 'بدعم من {castopod}', + 'actions' => 'الإجراءات', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'العودة', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'معاينة', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'اضغط للاختيار', + 'loadingText' => 'جارٍ التحميل…', + 'noResultsText' => 'لم يتم العثور على نتائج', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'إرسال ملف', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'تشغيل', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/ar/Countries.php b/modules/Admin/Language/ar/Countries.php new file mode 100644 index 00000000..6a111a23 --- /dev/null +++ b/modules/Admin/Language/ar/Countries.php @@ -0,0 +1,264 @@ + 'أندورا', + 'AE' => 'الإمارات العربية المتحدة', + 'AF' => 'أفغانستان', + 'AG' => 'أنتيغا وباربودا', + 'AI' => 'Anguilla', + 'AL' => 'ألبانيا', + 'AM' => 'أرمينيا', + 'AO' => 'أنغولا', + 'AQ' => 'القارة القطبية الجنوبية', + 'AR' => 'الأرجنتين', + 'AS' => 'American Samoa', + 'AT' => 'النمسا', + 'AU' => 'أستراليا', + 'AW' => 'آروبا', + 'AX' => 'جزر آلاند', + 'AZ' => 'أذربيدجان', + 'BA' => 'البوسنة والهرسك', + 'BB' => 'بربادوس', + 'BD' => 'بنغلاديش', + 'BE' => 'بلجيكا', + 'BF' => 'بوركينا فاسو', + 'BG' => 'بلغاريا', + 'BH' => 'البحرين', + 'BI' => 'بورندي', + 'BJ' => 'البينين', + 'BL' => 'سان بارتيليمي', + 'BM' => 'برمودا', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'البرازيل', + 'BS' => 'الباهاماس', + 'BT' => 'بوتان', + 'BV' => 'Bouvet Island', + 'BW' => 'بوتسوانا', + 'BY' => 'بيلاروسيا', + 'BZ' => 'بليز', + 'CA' => 'كندا', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'الكونغو، جمهورية الكونغو الديمقراطية', + 'CF' => 'جمهورية أفريقيا الوسطى', + 'CG' => 'الكونغو', + 'CH' => 'سويسرا', + 'CI' => "كوت ديفوار", + 'CK' => 'جزر كوك', + 'CL' => 'الشيلي', + 'CM' => 'الكاميرون', + 'CN' => 'الصين', + 'CO' => 'كولومبيا', + 'CR' => 'كوستا ريكا', + 'CU' => 'كوبا', + 'CV' => 'الرأس الأخضر', + 'CW' => 'كوراساو', + 'CX' => 'جزيرة كريستماس', + 'CY' => 'قبرص', + 'CZ' => 'جمهورية التشيك', + 'DE' => 'ألمانيا', + 'DJ' => 'جيبوتي', + 'DK' => 'الدانمارك', + 'DM' => 'Dominica', + 'DO' => 'جمهورية الدومينكان', + 'DZ' => 'الجزائر', + 'EC' => 'الإكوادور', + 'EE' => 'إستونيا', + 'EG' => 'مصر', + 'EH' => 'الصحراء الغربية', + 'ER' => 'إريتريا', + 'ES' => 'إسبانيا', + 'ET' => 'إثيوبيا', + 'FI' => 'فنلندا', + 'FJ' => 'فيجي', + 'FK' => 'جزر فوكلاند (مالفيناس)', + 'FM' => 'دول ميكرونيزيا الفيدرالية', + 'FO' => 'جزر فاراو', + 'FR' => 'فرنسا', + 'GA' => 'الغابون', + 'GB' => 'المملكة المتحدة', + 'GD' => 'غرناطة', + 'GE' => 'جورجيا', + 'GF' => 'غويانا الفرنسية', + 'GG' => 'غيرنسي', + 'GH' => 'غانا', + 'GI' => 'جبل طارق', + 'GL' => 'غرينلاند', + 'GM' => 'غامبيا', + 'GN' => 'غينيا', + 'GP' => 'غوادلوب', + 'GQ' => 'غينيا الاستوائية', + 'GR' => 'اليونان', + 'GS' => 'جورجيا الجنوبية وجزر ساندويتش الجنوبية', + 'GT' => 'غواتيمالا', + 'GU' => 'غوام', + 'GW' => 'غينيا بيساو', + 'GY' => 'غويانا', + 'HK' => 'هونغ كونغ', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'الهندوراس', + 'HR' => 'كرواتيا', + 'HT' => 'هاييتي', + 'HU' => 'هنغاريا', + 'ID' => 'أندونيسيا', + 'IE' => 'إيرلندا', + 'IL' => 'إسرائيل', + 'IM' => 'جزيرة مان', + 'IN' => 'الهند', + 'IO' => 'إقليم المحيط الهندي البريطاني', + 'IQ' => 'العراق', + 'IR' => 'جمهورة إيران الإسلامية', + 'IS' => 'آيسلندا', + 'IT' => 'إيطاليا', + 'JE' => 'جيرسي', + 'JM' => 'جامايكا', + 'JO' => 'الأردن', + 'JP' => 'اليابان', + 'KE' => 'كينيا', + 'KG' => 'كيرغيزستان', + 'KH' => 'كمبوديا', + 'KI' => 'كيريباتي', + 'KM' => 'جزر القمر', + 'KN' => 'جزيرة سانت كيتس ونيفيس', + 'KP' => "جمهورية كوريا الشعبية الديمقراطية", + 'KR' => 'جمهورية كوريا', + 'KW' => 'الكويت', + 'KY' => 'جزر كايمان', + 'KZ' => 'كازاخستان', + 'LA' => "جمهورية لاو الديمقراطية الشعبية", + 'LB' => 'لبنان', + 'LC' => 'Saint Lucia', + 'LI' => 'ليشتنشتاين', + 'LK' => 'سريلانكا', + 'LR' => 'ليبيريا', + 'LS' => 'ليسوتو', + 'LT' => 'ليتوانيا', + 'LU' => 'لوكسمبورغ', + 'LV' => 'لاتفيا', + 'LY' => 'ليبيا', + 'MA' => 'المغرب', + 'MC' => 'موناكو', + 'MD' => 'جمهورية مولدوفا', + 'ME' => 'مونتنغرو', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'مدغشقر', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'مالي', + 'MM' => 'ميانمار', + 'MN' => 'منغوليا', + 'MO' => 'ماكاو', + 'MP' => 'جزر ماريانا الشمالية', + 'MQ' => 'Martinique', + 'MR' => 'موريتانيا', + 'MS' => 'مونتسيرات', + 'MT' => 'مالطا', + 'MU' => 'موريشيوس', + 'MV' => 'جزر المالديف', + 'MW' => 'مالاوي', + 'MX' => 'المكسيك', + 'MY' => 'ماليزيا', + 'MZ' => 'الموزمبيق', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'ناميبيا', + 'NC' => 'كاليدونيا الجديدة', + 'NE' => 'النيجر', + 'NF' => 'جزيرة نورفولك', + 'NG' => 'نيجيريا', + 'NI' => 'نيكاراغوا', + 'NL' => 'هولندا', + 'NO' => 'النرويج', + 'NP' => 'النيبال', + 'NR' => 'ناورو', + 'NU' => 'نييوي', + 'NZ' => 'نيوزيلاندا', + 'OM' => 'عمان', + 'PA' => 'باناما', + 'PE' => 'البيرو', + 'PF' => 'بولينيزيا الفرنسية', + 'PG' => 'بابوا غينيا الجديدة', + 'PH' => 'الفيليبين', + 'PK' => 'باكستان', + 'PL' => 'بولندا', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'دولة فلسطين', + 'PT' => 'البرتغال', + 'PW' => 'بالاو', + 'PY' => 'البراغواي', + 'QA' => 'قطر', + 'RE' => 'Réunion', + 'RO' => 'رومانيا', + 'RS' => 'صربيا', + 'RU' => 'روسيا الاتحادية', + 'RW' => 'رواندا', + 'SA' => 'العربية السعودية', + 'SB' => 'جزر سليمان', + 'SC' => 'سيشيل', + 'SD' => 'السودان', + 'SE' => 'السويد', + 'SG' => 'سنغافورة', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'سلوفينيا', + 'SJ' => 'سفالبارد ويان ماين', + 'SK' => 'سلوفاكيا', + 'SL' => 'سيراليون', + 'SM' => 'سان مارينو', + 'SN' => 'السنغال', + 'SO' => 'الصومال', + 'SR' => 'سورينام', + 'SS' => 'جنوب السودان', + 'ST' => 'ساو تومي وبرينسيبي', + 'SV' => 'السلفادور', + 'SX' => 'سانت مارتن (الجانب الهولندي)', + 'SY' => 'الجمهورية العربية السورية', + 'SZ' => 'سوازيلاند', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'تشاد', + 'TF' => 'الأقاليم الجنوبية الفرنسية', + 'TG' => 'توغو', + 'TH' => 'تايلاندا', + 'TJ' => 'طاجيكستان', + 'TK' => 'التوكيلاو', + 'TL' => 'تيمور الشرقية', + 'TM' => 'تركمنستان', + 'TN' => 'تونس', + 'TO' => 'تونغا', + 'TR' => 'تركيا', + 'TT' => 'ترينيداد وتوباغو', + 'TV' => 'توفالو', + 'TW' => 'تايوان، مقاطعة الصين', + 'TZ' => 'تنزانيا، الجمهورية المتحدة', + 'UA' => 'أوكرانيا', + 'UG' => 'أوغندا', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'الولايات المتحدة', + 'UY' => 'الأورغواي', + 'UZ' => 'أوزباكستان', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'الجزر العذراء الأمريكية', + 'VN' => 'الفييتنام', + 'VU' => 'فانواتو', + 'WF' => 'جزر واليس وفوتونا', + 'WS' => 'ساموا', + 'YE' => 'اليمن', + 'YT' => 'مايوت', + 'ZA' => 'جنوب أفريقيا', + 'ZM' => 'زامبيا', + 'ZW' => 'زيمبابوي', +]; diff --git a/modules/Admin/Language/ar/Dashboard.php b/modules/Admin/Language/ar/Dashboard.php new file mode 100644 index 00000000..7a84c9ce --- /dev/null +++ b/modules/Admin/Language/ar/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'البودكاستات', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'الحلقات', + 'not_found' => 'لا توجد حلقة منشورة', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'تخزين', + 'subtitle' => '{totalUploaded} من أصل {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ar/Episode.php b/modules/Admin/Language/ar/Episode.php new file mode 100644 index 00000000..1a1cdeeb --- /dev/null +++ b/modules/Admin/Language/ar/Episode.php @@ -0,0 +1,225 @@ + 'الموسم {seasonNumber}', + 'season_abbr' => 'م{seasonNumber}', + 'number' => 'الحلقة {episodeNumber}', + 'number_abbr' => 'الحلقة {episodeNumber}', + 'season_episode' => 'الموسم {seasonNumber} الحلقة {episodeNumber}', + 'season_episode_abbr' => 'م{seasonNumber}ح{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'كافة حلقات البودكاست', + 'back_to_podcast' => 'العودة إلى البودكاست', + 'edit' => 'تعديل', + 'preview' => 'Preview', + 'publish' => 'نشر', + 'publish_edit' => 'تعديل المنشور', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'إلغاء النشر', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'الحلقة غير منشورة.', + 'delete' => 'احذف', + 'go_to_page' => 'الانتقال إلى الصفحة', + 'create' => 'إضافة حلقة', + 'publication_status' => [ + 'published' => 'نُشِرَت', + 'with_podcast' => 'Published', + 'scheduled' => 'مُبَرمَجة', + 'not_published' => 'غير منشورة', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'البحث عن حلقة', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'الحلقة', + 'visibility' => 'الظهور', + 'downloads' => 'Downloads', + 'comments' => 'التعليقات', + 'actions' => 'الإجراءات', + ], + 'messages' => [ + 'createSuccess' => 'تم إنشاء الحلقة بنجاح!', + 'editSuccess' => 'تم تحديث الحلقة بنجاح!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'تم إلغاء نشر الحلقة بنجاح!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'الموعد المحدد يجب أن لا يكون فارغا!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'ملف صوتي', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'معلومات الحلقة', + 'cover' => 'غلاف الحلقة', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'العنوان', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'الرابط الدائم', + 'season_number' => 'الموسم', + 'episode_number' => 'الحلقة', + 'type' => [ + 'label' => 'النوع', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'عرض الملاحظات', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'الوصف', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'ملفات إضافية', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'الفصول', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'إنشاء حلقة', + 'submit_edit' => 'حفظ الحلقة', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'اكتب رسالتك…', + 'publication_date' => 'تاريخ النشر', + 'publication_method' => [ + 'now' => 'الآن', + 'schedule' => 'برمجة', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'تعديل المنشور', + 'cancel_publication' => 'إلغاء المنشور', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'إلغاء النشر', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'داكن', + 'dark-transparent' => 'داكن شفاف', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ar/EpisodeNavigation.php b/modules/Admin/Language/ar/EpisodeNavigation.php new file mode 100644 index 00000000..33409c67 --- /dev/null +++ b/modules/Admin/Language/ar/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'الرئيسية', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'مقاطع فيديو', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/ar/Fediverse.php b/modules/Admin/Language/ar/Fediverse.php new file mode 100644 index 00000000..7e8e1876 --- /dev/null +++ b/modules/Admin/Language/ar/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'اسم النطاق', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'الحساب', + 'domain' => 'اسم النطاق', + 'unblock' => 'ألغ الحجب', + ], +]; diff --git a/modules/Admin/Language/ar/Home.php b/modules/Admin/Language/ar/Home.php new file mode 100644 index 00000000..c0833c89 --- /dev/null +++ b/modules/Admin/Language/ar/Home.php @@ -0,0 +1,14 @@ + 'كافة البودكاستات', + 'no_podcast' => 'لا يوجد أي بودكاست', +]; diff --git a/modules/Admin/Language/ar/Install.php b/modules/Admin/Language/ar/Install.php new file mode 100644 index 00000000..ffca0943 --- /dev/null +++ b/modules/Admin/Language/ar/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'اسم المضيف', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'اسم مضيف قاعدة البيانات', + 'db_name' => 'اسم قاعدة البيانات', + 'db_username' => 'اسم المستخدم لقاعدة البيانات', + 'db_password' => 'كلمة مرور قاعدة البيانات', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'ملف', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'التالي', + 'submit' => 'إنهاء التثبيت', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'البريد الإلكتروني', + 'username' => 'اسم المستخدم', + 'password' => 'كلمة المرور', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/ar/Navigation.php b/modules/Admin/Language/ar/Navigation.php new file mode 100644 index 00000000..6a8bd0fa --- /dev/null +++ b/modules/Admin/Language/ar/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'الانتقال إلى موقع الويب', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'لوحة التحكم', + 'admin' => 'الرئيسية', + 'podcasts' => 'البودكاستات', + 'podcast-list' => 'كافة البودكاستات', + 'podcast-create' => 'بودكاست جديد', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'أشخاص', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'الفديفرس', + 'fediverse-blocked-actors' => 'الحسابات المحظورة', + 'fediverse-blocked-domains' => 'النطاقات المحظورة', + 'users' => 'مستخدمون', + 'user-list' => 'كافة المستخدمين', + 'user-create' => 'مستخدم جديد', + 'pages' => 'الصفحات', + 'page-list' => 'كافة الصفحات', + 'page-create' => 'صفحة جديدة', + 'settings' => 'الإعدادات', + 'settings-general' => 'العامة', + 'settings-theme' => 'الحلة', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'حسابي', + 'change-password' => 'تغيير الكلمة السرية', + 'logout' => 'خروج', + ], +]; diff --git a/modules/Admin/Language/ar/Notifications.php b/modules/Admin/Language/ar/Notifications.php new file mode 100644 index 00000000..8e86a2b3 --- /dev/null +++ b/modules/Admin/Language/ar/Notifications.php @@ -0,0 +1,19 @@ + 'الإشعارات', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'لا توجد إشعارات', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/ar/Page.php b/modules/Admin/Language/ar/Page.php new file mode 100644 index 00000000..31dde5a1 --- /dev/null +++ b/modules/Admin/Language/ar/Page.php @@ -0,0 +1,30 @@ + 'العودة إلى الصفحة الرئيسية', + 'page' => 'الصفحة', + 'all_pages' => 'كافة الصفحات', + 'create' => 'صفحة جديدة', + 'go_to_page' => 'الانتقال إلى الصفحة', + 'edit' => 'تعديل الصفحة', + 'delete' => 'احذف الصفحة', + 'form' => [ + 'title' => 'العنوان', + 'permalink' => 'الوصلة الدائمة', + 'content' => 'المحتوى', + 'submit_create' => 'إنشاء صفحة', + 'submit_edit' => 'حفظ', + ], + 'messages' => [ + 'createSuccess' => 'تم إنشاء الصفحة "{pageTitle}" بنجاح!', + 'editSuccess' => 'تم تحديث الصفحة بنجاح!', + ], +]; diff --git a/modules/Admin/Language/ar/Pager.php b/modules/Admin/Language/ar/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/ar/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/ar/Person.php b/modules/Admin/Language/ar/Person.php new file mode 100644 index 00000000..95140270 --- /dev/null +++ b/modules/Admin/Language/ar/Person.php @@ -0,0 +1,65 @@ + 'أشخاص', + 'all_persons' => 'All persons', + 'no_person' => 'لم يعثر على أحد!', + 'create' => 'إنشاء شخص', + 'view' => 'عرض شخص', + 'edit' => 'Edit person', + 'delete' => 'حذف شخص', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'تم تحديث الشخص بنجاح!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'الصورة الرمزية', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'الإسم الكامل', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'تستخدم للروابط', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'إنشاء شخص', + 'submit_edit' => 'حفظ الشخص', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'الأدوار', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'الأدوار', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/ar/Platforms.php b/modules/Admin/Language/ar/Platforms.php new file mode 100644 index 00000000..7c01243d --- /dev/null +++ b/modules/Admin/Language/ar/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'حفظ', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/ar/Podcast.php b/modules/Admin/Language/ar/Podcast.php new file mode 100644 index 00000000..08ebcdd4 --- /dev/null +++ b/modules/Admin/Language/ar/Podcast.php @@ -0,0 +1,330 @@ + 'كافة البودكاستات', + 'no_podcast' => 'No podcast found!', + 'create' => 'إنشاء بودكاست', + 'import' => 'استيراد بودكاست', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'حلقة جديدة', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'الانتقال إلى الصفحة', + 'latest_episodes' => 'أحدث الحلقات', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'العنوان', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'الوصف', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'اللغة', + 'category' => 'الفئة', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'حقوق التأليف', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'الإعدادات المتقدمة', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'موسيقى', + 'news' => 'أخبار', + 'religion_and_spirituality' => 'دين وروحانيات', + 'science' => 'علوم', + 'society_and_culture' => 'مجتمع وثقافة', + 'sports' => 'رياضة', + 'technology' => 'تكنولوجيا', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'كتب', + 'design' => 'تصميم', + 'fashion_and_beauty' => 'أزياء وجمال', + 'food' => 'طعام', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'تعلم اللغات', + 'self_improvement' => 'تطوير الذات', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'ألعاب', + 'hobbies' => 'هوايات', + 'home_and_garden' => 'المنزل والحديقة', + 'video_games' => 'ألعاب الفيديو', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'سياسة', + 'sports_news' => 'أخبار رياضية', + 'tech_news' => 'أخبار التكنولوجيا', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'إسلام', + 'judaism' => 'يهودية', + 'religion' => 'دين', + 'spirituality' => 'روحانيات', + 'astronomy' => 'علم الفلك', + 'chemistry' => 'كيمياء', + 'earth_sciences' => 'علوم الأرض', + 'life_sciences' => 'علوم الحياة', + 'mathematics' => 'الرياضيات', + 'natural_sciences' => 'العلوم الطبيعية', + 'nature' => 'الطبيعة', + 'physics' => 'الفيزياء', + 'social_sciences' => 'العلوم الاجتماعية', + 'documentary' => 'وثائقي', + 'personal_journals' => 'يوميات شخصية', + 'philosophy' => 'الفلسفة', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'العلاقات', + 'baseball' => 'Baseball', + 'basketball' => 'كرة السلة', + 'cricket' => 'الكريكيت', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'كرة القدم', + 'golf' => 'الغولف', + 'hockey' => 'الهوكي', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'كرة القدم', + 'swimming' => 'السباحة', + 'tennis' => 'Tennis', + 'volleyball' => 'الكرة الطائرة', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'الحلقات', + 'sponsor' => 'الراعي', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/ar/PodcastNavigation.php b/modules/Admin/Language/ar/PodcastNavigation.php new file mode 100644 index 00000000..b82f78d9 --- /dev/null +++ b/modules/Admin/Language/ar/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'انتقل إلى صفحة البودكاست', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'الرئيسية', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'الحلقات', + 'episode-list' => 'جميع الحلقات', + 'episode-create' => 'حلقة جديدة', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'المساهمون', + 'contributor-list' => 'كل المساهمين', + 'contributor-add' => 'إضافة مساهم', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ar/Settings.php b/modules/Admin/Language/ar/Settings.php new file mode 100644 index 00000000..6cd61799 --- /dev/null +++ b/modules/Admin/Language/ar/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'حفظ', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'الصور', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'الحلة', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'حفظ', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/ar/Soundbite.php b/modules/Admin/Language/ar/Soundbite.php new file mode 100644 index 00000000..7e7818b0 --- /dev/null +++ b/modules/Admin/Language/ar/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'المدة الزمنية', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/ar/Validation.php b/modules/Admin/Language/ar/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/ar/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ar/VideoClip.php b/modules/Admin/Language/ar/VideoClip.php new file mode 100644 index 00000000..5ed98d69 --- /dev/null +++ b/modules/Admin/Language/ar/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'المدة الزمنية', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/br/AboutCastopod.php b/modules/Admin/Language/br/AboutCastopod.php new file mode 100644 index 00000000..d0f56d6b --- /dev/null +++ b/modules/Admin/Language/br/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Diwar-benn Castopod', + 'host_name' => 'Anv an ostiz', + 'version' => 'Stumm Castopod', + 'php_version' => 'Stumm PHP', + 'os' => 'Sistem oberiañ', + 'languages' => 'Yezhoù', + 'update_database' => 'Nevesaat an diaz roadennoù', + 'messages' => [ + 'databaseUpdateSuccess' => 'Nevesaet eo an diaz roadennoù!', + ], +]; diff --git a/modules/Admin/Language/br/Breadcrumb.php b/modules/Admin/Language/br/Breadcrumb.php new file mode 100644 index 00000000..65d62836 --- /dev/null +++ b/modules/Admin/Language/br/Breadcrumb.php @@ -0,0 +1,57 @@ + 'roll-istor', + config('Admin') + ->gateway => 'Degemer', + 'podcasts' => 'podkastoù', + 'episodes' => 'rannoù', + 'subscriptions' => 'koumanantoù', + 'contributors' => 'perzhidi, perzhiadezed', + 'pages' => 'pajennoù', + 'settings' => 'arventennoù', + 'theme' => 'neuz', + 'about' => 'a-zivout', + 'add' => 'ouzhpennañ', + 'new' => 'krouiñ', + 'edit' => 'kemmañ', + 'persons' => 'emellerien·ezed', + 'publish' => 'embann', + 'publish-edit' => 'kemmañ an embannadur', + 'publish-date-edit' => 'kemmañ deiziad an embannadur', + 'unpublish' => 'diembannañ', + 'delete' => 'dilemel', + 'remove' => 'lemel', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'aktourien·ezed stanket', + 'blocked-domains' => 'domanioù stanket', + 'users' => 'implijerien·ezed', + 'my-account' => 'ma c\'hont', + 'change-password' => 'kemmañ ar ger-tremen', + 'imports' => 'enporzhiadennoù', + 'sync-feeds' => 'sinkronekaat ar gwazhoù', + 'platforms' => 'savennoù', + 'social' => 'rouedadoù sokial', + 'funding' => 'arc\'hantaouiñ', + 'monetization-other' => 'doare arc\'hantaouiñ all', + 'analytics' => 'muzulioù heklev', + 'locations' => 'lec\'hioù', + 'webpages' => 'pajennoù web', + 'unique-listeners' => 'selaouerien·ezed unel', + 'players' => 'lennerioù', + 'listening-time' => 'padelezh ar selaou', + 'time-periods' => 'mareoù ar selaou', + 'soundbites' => 'tennadoù son', + 'video-clips' => 'klipoù video', + 'embed' => 'lenner enkorfet', + 'notifications' => 'kemennoù', + 'suspend' => 'ehanañ', +]; diff --git a/modules/Admin/Language/br/Charts.php b/modules/Admin/Language/br/Charts.php new file mode 100644 index 00000000..687ea057 --- /dev/null +++ b/modules/Admin/Language/br/Charts.php @@ -0,0 +1,41 @@ + 'Pellgargadurioù ar rannoù dre servij (e-pad ar sizhunvezh tremenet)', + 'by_player_weekly' => 'Pellgargadurioù ar rannoù dre lenner (e-pad ar sizhunvezh tremenet)', + 'by_player_yearly' => 'Pellgargadurioù ar rannoù dre servij (e-pad ar bloavezh tremenet)', + 'by_device_weekly' => 'Pellgargadurioù ar rannoù dre venveg (e-pad ar sizhunvezh tremenet)', + 'by_os_weekly' => 'Pellgargadurioù ar rannoù dre OS (e-pad ar sizhunvezh tremenet)', + 'podcast_by_region' => 'Pellgargadurioù ar rannoù dre vro (e-pad ar sizhunvezh tremenet)', + 'unique_daily_listeners' => 'Selaouerien·ezed unel pemdeziek', + 'unique_monthly_listeners' => 'Selaouerien·ezed unel miziek', + 'by_browser' => 'Darempred gant ar pajennoù web dre verdeer (e-pad ar sizhun tremenet)', + 'podcast_by_day' => 'Pellgargadurioù pemdeziek ar rannoù', + 'podcast_by_month' => 'Pellgargadurioù miziek ar rannoù', + 'episode_by_day' => 'Pellgargadurioù pemdeziek ar rannoù (an 60 deizioù kentañ)', + 'episode_by_month' => 'Pellgargadurioù miziek ar rannoù', + 'episodes_by_day' => + 'Pellgargadurioù ar 5 rannoù diwezhañ (an 60 deizioù kentañ)', + 'by_country_weekly' => 'Pellgargadurioù ar rannoù dre vro (e-pad ar sizhunvezh tremenet)', + 'by_country_yearly' => 'Pellgargadurioù ar rannoù dre vro (e-pad ar bloavezh tremenet)', + 'by_domain_weekly' => 'Darempred gant ar pajennoù web dre orin (e-pad ar sizhun tremenet)', + 'by_domain_yearly' => 'Darempred gant ar pajennoù web dre orin (e-pad ar bloavezh tremenet)', + 'by_entry_page' => 'Darempred gant ar pajennoù web dre bajenn vont-tre (e-pad ar sizhun tremenet)', + 'podcast_bots' => 'Robotoù (crawlers)', + 'daily_listening_time' => 'Sammad pemdeziek ar badelezh selaou', + 'monthly_listening_time' => 'Sammad miziek ar badelezh selaou', + 'by_weekday' => 'Dre zeiz ar sizhun (e-pad an 60 devezh diwezhañ)', + 'by_hour' => 'Dre eur an devezh (e-pad an 60 devezh diwezhañ)', + 'podcast_by_bandwidth' => 'Lec\'hed bann implijet bemdez (e MB)', + 'total_storage_by_month' => 'Kadaviñ bep miz (e MB)', + 'total_bandwidth_by_month' => 'Lec\'hed bann implijet bep miz (e MB)', + 'total_bandwidth_by_month_limit' => 'Bevennet da {totalBandwidth} bep miz', +]; diff --git a/modules/Admin/Language/br/Common.php b/modules/Admin/Language/br/Common.php new file mode 100644 index 00000000..40491496 --- /dev/null +++ b/modules/Admin/Language/br/Common.php @@ -0,0 +1,52 @@ + 'Ya', + 'no' => 'Ket', + 'cancel' => 'Nullañ', + 'optional' => 'Diret', + 'more' => 'Muioc\'h', + 'no_data' => 'Roadenn ebet kavet !', + 'close' => 'Serriñ', + 'edit' => 'Kemmañ', + 'copy' => 'Eilañ', + 'copied' => 'Eilet!', + 'home' => 'Degemer', + 'explicit' => 'Danvez evit an oadourien', + 'powered_by' => 'Lusket gant {castopod}', + 'actions' => 'Obererezhioù', + 'pageInfo' => 'Pajenn {currentPage} diwar {pageCount}', + 'go_back' => 'Mont war-gil', + 'forms' => [ + 'editor' => [ + 'write' => 'Skrivañ', + 'preview' => 'Alberz', + 'help' => 'Lusket gant markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Pouezañ da ziuzañ', + 'loadingText' => 'O kargañ…', + 'noResultsText' => 'Disoc\'h ebet kavet', + 'noChoicesText' => 'N\'eus dibab ebet da ziuzañ', + 'maxItemText' => 'N\'haller ket ouzhpennañ elfennoù all', + ], + 'upload_file' => 'Uskargit ur restr', + 'remote_url' => 'URL a-bell', + 'save' => 'Enrollañ', + ], + 'play_episode_button' => [ + 'play' => 'Lenn', + 'playing' => 'O lenn', + ], + 'size_limit' => 'Bevenn ar vent: {0}.', + 'choose_interact' => 'Dibabit penaos bezañ e darempred', + 'view' => 'Gwelet', +]; diff --git a/modules/Admin/Language/br/Countries.php b/modules/Admin/Language/br/Countries.php new file mode 100644 index 00000000..229abb0d --- /dev/null +++ b/modules/Admin/Language/br/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emirelezhioù-Arab-Unanet', + 'AF' => 'Afganistan', + 'AG' => 'Antigua ha Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albani', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarktik', + 'AR' => 'Arc\'hantin', + 'AS' => 'Samoa Amerikan', + 'AT' => 'Aostria', + 'AU' => 'Aostralia', + 'AW' => 'Aruba', + 'AX' => 'Åland, Inizi', + 'AZ' => 'Azerbaidjan', + 'BA' => 'Bosnia ha Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgia', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgari', + 'BH' => 'Bahrein', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Sant-Barteleme', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Stad Liesvroadel', + 'BQ' => 'Bonaire, Sint Eustatius ha Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhoutan', + 'BV' => 'Bouvet, Inez', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Cocos (Keeleng), Inizi', + 'CD' => 'Republik Demokratel Kongo', + 'CF' => 'Kreizafrikan, Republik', + 'CG' => 'Kongo', + 'CH' => 'Suis', + 'CI' => "Aod an Olifant", + 'CK' => 'Inizi Cook', + 'CL' => 'Chile', + 'CM' => 'Kameroun', + 'CN' => 'Sina', + 'CO' => 'Kolombia', + 'CR' => 'Costa Rica', + 'CU' => 'Kuba', + 'CV' => 'Kab Glas', + 'CW' => 'Kòrsou', + 'CX' => 'Christmas, Enez', + 'CY' => 'Kiprenez', + 'CZ' => 'Tchekia', + 'DE' => 'Alamagn', + 'DJ' => 'Djibouti', + 'DK' => 'Danmark', + 'DM' => 'Dominika', + 'DO' => 'Dominikan, Republik', + 'DZ' => 'Aljeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egipt', + 'EH' => 'Sahara ar C\'hornôg', + 'ER' => 'Eritrea', + 'ES' => 'Spagn', + 'ET' => 'Etiopia', + 'FI' => 'Finland', + 'FJ' => 'Fidji', + 'FK' => 'Maloù, Inizi (Malvinas)', + 'FM' => 'Mikronezia, Stadoù Kevreet', + 'FO' => 'Faroe, Inizi', + 'FR' => 'Bro-C\'hall', + 'GA' => 'Gabon', + 'GB' => 'Rouantelezh Unanet', + 'GD' => 'Grenada', + 'GE' => 'Jorjia', + 'GF' => 'Gwian', + 'GG' => 'Gwernenez', + 'GH' => 'Ghana', + 'GI' => 'Jibraltar', + 'GL' => 'Greunland', + 'GM' => 'Gambia', + 'GN' => 'Ginea', + 'GP' => 'Gwadeloup', + 'GQ' => 'Republik Ginea', + 'GR' => 'Gres', + 'GS' => 'Georgia ar Su hag Inizi Sandwich ar Su', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Ginea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard ha McDonald, Inizi', + 'HN' => 'Honduras', + 'HR' => 'Koatia', + 'HT' => 'Haiti', + 'HU' => 'Hungaria', + 'ID' => 'Indonezia', + 'IE' => 'Iwerzhon', + 'IL' => 'Israel', + 'IM' => 'Enez-Vanav', + 'IN' => 'Indez', + 'IO' => 'Tiriad Meurvor Indez Breizh-Veur', + 'IQ' => 'Irak', + 'IR' => 'Iran', + 'IS' => 'Island', + 'IT' => 'Italia', + 'JE' => 'Jerzenez', + 'JM' => 'Jamaika', + 'JO' => 'Jordani', + 'JP' => 'Japon', + 'KE' => 'Kenya', + 'KG' => 'Kirgizstan', + 'KH' => 'Kambodj', + 'KI' => 'Kiribati', + 'KM' => 'Komor', + 'KN' => 'Sant Kitts ha Nevis', + 'KP' => "Korea, Republik Demokratel ha Poblel", + 'KR' => 'Korea, Republik', + 'KW' => 'Kowait', + 'KY' => 'Cayman, Inizi', + 'KZ' => 'Kazakstan', + 'LA' => "Bro-Laos", + 'LB' => 'Liban', + 'LC' => 'Santez-Lusia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lituania', + 'LU' => 'Luksembourg', + 'LV' => 'Latvia', + 'LY' => 'Libia', + 'MA' => 'Maroko', + 'MC' => 'Monako', + 'MD' => 'Moldova, Republik', + 'ME' => 'Montenegro', + 'MF' => 'Saint-Martin', + 'MG' => 'Madagaskar', + 'MH' => 'Marshall, Inizi', + 'MK' => 'Makedonia, Republik', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Makao', + 'MP' => 'Mariana an Norzh, Inizi', + 'MQ' => 'Martinik', + 'MR' => 'Mauretania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Moris', + 'MV' => 'Maldivez', + 'MW' => 'Malawi', + 'MX' => 'Mec\'hiko', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambik', + 'N/A' => 'E-maez danvez (IP lec\'hel…)', + 'NA' => 'Namibia', + 'NC' => 'Kaledonia-Nevez', + 'NE' => 'Niger', + 'NF' => 'Norfolk, Enez', + 'NG' => 'Nijeria', + 'NI' => 'Nicaragua', + 'NL' => 'Izelvroioù', + 'NO' => 'Norvej', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Zeland Nevez', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Perou', + 'PF' => 'Polinezia C\'hall', + 'PG' => 'Papoua Ginea-Nevez', + 'PH' => 'Filipinez', + 'PK' => 'Pakistan', + 'PL' => 'Pologn', + 'PM' => 'Sant-Pêr-ha-Mikelon', + 'PN' => 'Pitcairn, Inizi', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestin', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Katar', + 'RE' => 'Ar Reünion', + 'RO' => 'Roumani', + 'RS' => 'Serbi', + 'RU' => 'Rusia, Kevread', + 'RW' => 'Rwanda', + 'SA' => 'Arabia Saoudat', + 'SB' => 'Inizi Solomon', + 'SC' => 'Sechelez', + 'SD' => 'Soudan', + 'SE' => 'Sveden', + 'SG' => 'Singapoura', + 'SH' => 'Saint Helena, Ascension ha Tristan da Cunha', + 'SI' => 'Sloveni', + 'SJ' => 'Svalbard ha Jan Mayen', + 'SK' => 'Slovaki', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Surinam', + 'SS' => 'Soudan ar Su', + 'ST' => 'São Tomé ha Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten', + 'SY' => 'Siria', + 'SZ' => 'Eswatini', + 'TC' => 'Turks ha Caicos, Inizi', + 'TD' => 'Tchad', + 'TF' => 'Douaroù Aostral hag Antarktikel Frañs', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tadjikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor ar Reter', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunizia', + 'TO' => 'Tonga', + 'TR' => 'Turkia', + 'TT' => 'Trinidad ha Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania, Republik Unanet', + 'UA' => 'Ukraina', + 'UG' => 'Ouganda', + 'UM' => 'Inizi bihan diabell ar Stadoù-Unanet', + 'US' => 'Stadoù-Unanet', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Vatikan', + 'VC' => 'Sant Visant hag an Inizi Granadinas', + 'VE' => 'Venezuela, Republik Volivarian', + 'VG' => 'Inizi Gwerc\'h Breizhveurat', + 'VI' => 'Inizi Gwerc\'h, S.U.', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis ha Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'Afrika ar Su', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/br/Dashboard.php b/modules/Admin/Language/br/Dashboard.php new file mode 100644 index 00000000..255e0aca --- /dev/null +++ b/modules/Admin/Language/br/Dashboard.php @@ -0,0 +1,28 @@ + 'Taolenn-stur', + 'welcome_message' => 'Degemer mat en daolenn-stur!', + 'podcasts' => [ + 'title' => 'Podkastoù', + 'not_found' => 'Podkast embannet ebet', + 'last_published' => 'Embannet da ziwezhañ d\'an/ar {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Rannoù', + 'not_found' => 'Rann embannet ebet', + 'last_published' => 'Embannet da ziwezhañ d\'an/ar {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Stokañ', + 'subtitle' => '{totalUploaded} war {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/br/Episode.php b/modules/Admin/Language/br/Episode.php new file mode 100644 index 00000000..7f73831b --- /dev/null +++ b/modules/Admin/Language/br/Episode.php @@ -0,0 +1,227 @@ + 'Koulzad {seasonNumber}', + 'season_abbr' => 'K{seasonNumber}', + 'number' => 'Rann {episodeNumber}', + 'number_abbr' => 'R. {episodeNumber}', + 'season_episode' => 'Koulzad {seasonNumber} rann {episodeNumber}', + 'season_episode_abbr' => 'K{seasonNumber}R{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + 0 {evezhiadenn ebet} + one {# evezhiadenn} + other {# evezhiadenn} + }', + 'all_podcast_episodes' => 'Holl rannoù ar podkast', + 'back_to_podcast' => 'Mont d\'ar podkast en-dro', + 'edit' => 'Kemmañ', + 'preview' => 'Rakwel', + 'publish' => 'Embann', + 'publish_edit' => 'Kemmañ an embannadur', + 'publish_date_edit' => 'Kemmañ deiziad an embannadur', + 'unpublish' => 'Diembannañ', + 'publish_error' => 'Embannet eo bet ar rann dija.', + 'publish_edit_error' => 'Embannet eo bet ar rann dija.', + 'publish_cancel_error' => 'Embannet eo bet ar rann dija.', + 'publish_date_edit_error' => 'N\'eo ket bet embannet ar podkast c\'hoazh, ne c\'hallit ket kemmañ an deiziad an embann.', + 'publish_date_edit_future_error' => 'Rankout a ra deiziad embannadur ar rann bezañ en amzer dremenet! M\'ho peus c\'hoant da steuñviñ an embannadur en amzer da zont e rankit diembann ar rann da gentañ.', + 'publish_date_edit_success' => 'Cheñchet eo bet deiziad embannadur ar rann gant berzh!', + 'unpublish_error' => 'N\'eo ket bet embannet ar rann.', + 'delete' => 'Dilemel', + 'go_to_page' => 'Gwelet ar bajenn', + 'create' => 'Ouzhpennañ ur rann', + 'publication_status' => [ + 'published' => 'Embannet', + 'with_podcast' => 'Embannet', + 'scheduled' => 'Steuñvet', + 'not_published' => 'Diembann', + ], + 'with_podcast_hint' => 'Embannet e vo war un dro gant ar podkast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Klask ur rann', + 'clear' => 'Diverkañ an enklask', + 'submit' => 'Klask', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + 0 {rann ebet} + one {# rann} + other {# rann} + }', + 'episode' => 'Rann', + 'visibility' => 'Gwelusted', + 'downloads' => 'Pellgargadennoù', + 'comments' => 'Evezhiadennoù', + 'actions' => 'Obererezhioù', + ], + 'messages' => [ + 'createSuccess' => 'Krouet eo bet ar rann gant berzh!', + 'editSuccess' => 'Nevesaet eo bet ar rann gant berzh!', + 'publishSuccess' => '{publication_status, select, + published {Embannet eo bet ar rann gant berzh !} + scheduled {Raktreset eo bet embannadur ar rann gant berzh !} + with_podcast {Ar rann-mañ a vo embannet war un dro gant ar podkast.} + other {N\'eo ket bet embannet ar rann-mañ.} + }', + 'publishCancelSuccess' => 'Nullet eo bet embannadur ar rann gant berzh!', + 'unpublishBeforeDeleteTip' => 'Ret eo deoc\'h diembannañ ar rann a-raok dilemel anezhi.', + 'scheduleDateError' => 'Ret eo lakaat un deiziad evit an embannadur!', + 'deletePublishedEpisodeError' => 'Diembannit ar rann a-raok dilemel anezhi mar plij.', + 'deleteSuccess' => 'Dilamet eo bet ar rann gant berzh!', + 'deleteError' => 'C\'hwitadenn war dilemel {type, select, + transcript {treuzskrivadur} + chapters {chabistroù} + image {golo} + audio {aodio} + other {media} + } ar rann.', + 'deleteFileError' => 'C\'hwitadenn war dilemel restr {type, select, + transcript {an treuzskrivadur} + chapters {ar chabistroù} + image {ar golo} + audio {an aodio} + other {ar media} + } {file_key}. Gallout a rit lemel kuit ar restr-mañ diouzh ar gantenn dre zorn.', + 'sameSlugError' => 'Bez ez eus eus ur rann gant ar berradur-mañ (slug) dija.', + ], + 'form' => [ + 'file_size_error' => + 'Re vras eo ho restr! {0} eo ar braster uhelañ. Dav eo deoc\'h kreskaat an talvoudoù `memory_limit`, `upload_max_filesize` ha `post_max_size` en ho restr kefluniañ, a-raok adloc\'hañ ho tafariad web hag uskargañ ho restr.', + 'audio_file' => 'Restr aodio', + 'audio_file_hint' => 'Dibabit ur restr .mp3 pe .m4a.', + 'info_section_title' => 'Titouroù ar rann', + 'cover' => 'Golo ar rann', + 'cover_hint' => + 'Ma n\'ho peus ket kaset ur golo e vo implijet hini ar podkast en e blas.', + 'cover_size_hint' => 'Ar golo a rankfe bezañ ur c\'harrez ha 1400px e vent da nebeutañ.', + 'title' => 'Titl', + 'title_hint' => + 'Dleout a rafe anv ar rann, sklaer ha berr. Arabat lakaat niverenn ar rann pe ar c\'houlzad amañ.', + 'permalink' => 'Ere peurzalc\'hus', + 'season_number' => 'Koulzad', + 'episode_number' => 'Rann', + 'type' => [ + 'label' => 'Doare', + 'full' => 'Klok', + 'full_hint' => 'Rann a-bezh', + 'trailer' => 'Tañvadenn', + 'trailer_hint' => 'Tennad berr evit brudañ ar podkast', + 'bonus' => 'Bonuz', + 'bonus_hint' => 'Danvez ouzhpenn ar podkast (da skouer, titouroù diwar-benn kostezioù pe atersadennoù gant an aktourien·ezed), pe bruderezh kroaziet evit ur podkast all', + ], + 'premium_title' => 'Premium', + 'premium' => 'Ne vo gwelet ar rann nemet gant koumananterien·ezed Premium', + 'parental_advisory' => [ + 'label' => 'Kemenn evit ar gerent', + 'hint' => 'Hag ar rann-mañ a zo danvez ha ne zlefe ket gwelet gant bugale?', + 'undefined' => 'andermenet', + 'clean' => 'Dereat', + 'explicit' => 'Danvez evit an oadourien', + ], + 'show_notes_section_title' => 'Notennoù ar rann', + 'show_notes_section_subtitle' => + 'Betek 4000 arouez, sklaer ha berr. Notennoù a rann a c\'hell sikour selaouerien·ezed zo kavout anezhi.', + 'description' => 'Deskrivadur', + 'description_footer' => 'Traoñ an deskrivadur', + 'description_footer_hint' => + 'Emañ ouzhpennet an destenn-mañ e dibenn an holl rannoù. Ul lec\'h mat eo evit lakaat ereoù ho rouedadoù sokial da skouer.', + 'additional_files_section_title' => 'Restroù ouzhpenn', + 'additional_files_section_subtitle' => + 'Ar restroù-mañ a c\'hell bezañ implijet gant savennoù all evit aesaat an traoù d\'ho selaouerien·ezed. Sellit ouzh {podcastNamespaceLink} evit muioc\'h a ditouroù.', + 'location_section_title' => 'Lec\'h', + 'location_section_subtitle' => 'Eus peseurt lec\'h ez eus kaoz er rann-mañ?', + 'location_name' => 'Anv pe chomlec\'h al lec\'h', + 'location_name_hint' => 'Al lec\'h-mañ a c\'hell bezañ unan gwir pe unan faltaziet', + 'transcript' => 'Treuzskrivadur (istitloù)', + 'transcript_hint' => 'Aotreet e vez nemet .srt pe .vtt.', + 'transcript_download' => 'Pellgargañ an treuzskrivadur', + 'transcript_file' => 'Restr an treuzskrivadur (.srt pe .vtt)', + 'transcript_remote_url' => 'URL a-bell evit restr an treuzskrivadur', + 'transcript_file_delete' => 'Dilemel restr an treuzskrivadur', + 'chapters' => 'Chabistroù', + 'chapters_hint' => 'Dleout a ra ar restr bezañ er furmad JSON Chapters.', + 'chapters_download' => 'Pellgargañ ar chabistroù', + 'chapters_file' => 'Restr ar chabistroù', + 'chapters_remote_url' => 'URL a-bell evit restr ar chabistroù', + 'chapters_file_delete' => 'Dilemel restr ar chabistroù', + 'advanced_section_title' => 'Arventennoù kempleshoc\'h', + 'advanced_section_subtitle' => + 'M\'ho peus ezhomm eus balizennoù RSS ha n\'eus ket anezho e Castopod e c\'hellit o lakaat amañ.', + 'custom_rss' => 'Balizennoù RSS personelaet evit ar rann', + 'custom_rss_hint' => 'An dra-se a vo ouzhpennet e-barzh ar valizenn ❬item❭.', + 'block' => 'Ar rann-se a rankfe bezañ kuzhet diouzh ar rolladoù publik', + 'block_hint' => + 'Diskouez pe kuzhat ar rann: trec\'haoliñ an afell-mañ a viro ar rann-mañ ouzh bezañ diskouezet war Apple Podcasts, Google Podcasts pe savennoù all hag a implij ar renabloù-se. (N\'eus gwarant ebet)', + 'submit_create' => 'Krouiñ ar rann', + 'submit_edit' => 'Enrollañ ar rann', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Distreiñ da daolenn-stur ar rann', + 'post' => 'Ho kemennadenn vrudañ', + 'post_hint' => + "Skrivit ur gemennadenn evit brudañ embannadur ho rann. Skignet e vo ar gemennadenn-se d'an holl re a heuilh ac'hanoc'h war ar Fediverse ha lakaet e vo war well war pajenn ho podkast.", + 'message_placeholder' => 'Skrivit ho kemennadenn…', + 'publication_date' => 'Deiziad embannadur', + 'publication_method' => [ + 'now' => 'Bremañ', + 'schedule' => 'Steuñviñ', + 'with_podcast' => 'Embann asambles gant ar podkast', + ], + 'scheduled_publication_date' => 'Deiziad embannadur steuñvet', + 'scheduled_publication_date_clear' => 'Skarzhañ deiziad embannadur', + 'scheduled_publication_date_hint' => + 'Gallout a rit steuñviñ embannadur ar rann en ur steuñviñ embannadur ar rann en dazont. Dleout a ra ar vaezienn bezañ er furmad YYYY-MM-DD HH:mm', + 'submit' => 'Embann', + 'submit_edit' => 'Kemmañ an embann', + 'cancel_publication' => 'Nullañ an embannadur', + 'message_warning' => 'N\'ho peus ket skrivet ur gemennadenn evit brudañ ho rann!', + 'message_warning_hint' => 'Ouzhpennañ ur gemennadenn a lakay muioc\'h a dud er jeu, ha diwar se e vo gwelet muioc\'h ho rann.', + 'message_warning_submit' => 'Embann memestra', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Deiziad embannadur nevez', + 'new_publication_date_hint' => 'An dra-se a rank bezañ un deiziad tremenet.', + 'submit' => 'Kemmañ deiziad an embann', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Diembann ar rann a zilamo an holl gemennadennoù liammet outi ha skarzhet e vo eus gwazh RSS ar podkast.", + 'understand' => 'Komprennet eo, diembann ar rann a fell din', + 'submit' => 'Diembann', + ], + 'delete_form' => [ + 'disclaimer' => + "Gant ar rann e vo dilamet an holl restroù media, evezhiadennoù, klipoù video ha son liammet outi.", + 'understand' => 'Komprennet eo, dilemel ar rann a fell din', + 'submit' => 'Dilemel', + ], + 'embed' => [ + 'title' => 'Lenner enkorfet', + 'label' => + 'Dibabit ul liv evit an tem, eilit ar c\'hod er golver ha pegit anezhañ war ho lec\'hienn.', + 'clipboard_iframe' => 'Eilañ al lenner enkorfet er golver', + 'clipboard_url' => 'Eilañ ar chomlec\'h er golver', + 'dark' => 'Teñval', + 'dark-transparent' => 'Teñval treuzwelus', + 'light' => 'Sklaer', + 'light-transparent' => 'Sklaer treuzwelus', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'mod brouilhed', + 'text' => '{publication_status, select, + published {N\'eo ket bet embannet ar rann-mañ c\'hoazh.} + scheduled {Raktreset eo an embann a-benn an/ar {publication_date}.} + with_podcast {Ar rann-mañ a vo embannet war un dro gant ar podkast.} + other {N\'eo ket bet embannet ar rann-mañ c\'hoazh.} + }', + 'preview' => 'Rakwel', + ], +]; diff --git a/modules/Admin/Language/br/EpisodeNavigation.php b/modules/Admin/Language/br/EpisodeNavigation.php new file mode 100644 index 00000000..7f4c0afc --- /dev/null +++ b/modules/Admin/Language/br/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Gwelet pajenn ar rann', + 'dashboard' => 'Taolenn-stur ar rann', + 'episode-view' => 'Degemer', + 'episode-edit' => 'Kemm ar rann', + 'episode-persons-manage' => 'Merañ an emellerien·ezed', + 'embed-add' => 'Lenner enkorfet', + 'clips' => 'Klipoù', + 'video-clips-list' => 'Klipoù video', + 'video-clips-create' => 'Klip video nevez', + 'soundbites-list' => 'Tennadoù son', + 'soundbites-create' => 'Tennad son nevez', +]; diff --git a/modules/Admin/Language/br/Fediverse.php b/modules/Admin/Language/br/Fediverse.php new file mode 100644 index 00000000..f8aeebf4 --- /dev/null +++ b/modules/Admin/Language/br/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'N\'eo ket bet kavet ar gont-se !', + 'blockActorSuccess' => 'Stanket eo bet {actor}!', + 'unblockActorSuccess' => 'Distanket eo bet an implijer·ez!', + 'blockDomainSuccess' => 'Stanket eo bet {domain}!', + 'unblockDomainSuccess' => 'Distanket eo bet {domain}!', + ], + 'blocked_actors' => 'Implijerien·ezed stanket', + 'blocked_domains' => 'Domanioù stanket', + 'block_lists_form' => [ + 'handle' => 'Dornell (lesanv)', + 'handle_hint' => 'Skrivit @anv@domani an implijer·ez.', + 'domain' => 'Anv domani', + 'submit' => 'Stankañ!', + ], + 'list' => [ + 'actor' => 'Implijer·ez', + 'domain' => 'Anv domani', + 'unblock' => 'Distankañ', + ], +]; diff --git a/modules/Admin/Language/br/Home.php b/modules/Admin/Language/br/Home.php new file mode 100644 index 00000000..6cbea879 --- /dev/null +++ b/modules/Admin/Language/br/Home.php @@ -0,0 +1,14 @@ + 'An holl bodkastoù', + 'no_podcast' => 'N\'eus bet kavet podkast ebet', +]; diff --git a/modules/Admin/Language/br/Install.php b/modules/Admin/Language/br/Install.php new file mode 100644 index 00000000..2f86bafd --- /dev/null +++ b/modules/Admin/Language/br/Install.php @@ -0,0 +1,61 @@ + 'Kefluniañ dre zorn', + 'manual_config_subtitle' => + 'Krouit ur restr `.env` gant hoc’h arventennoù ha nevesait ar bajenn evit kenderc\'hel gant ar staliañ.', + 'form' => [ + 'instance_config' => 'Arventennoù an istañs', + 'hostname' => 'Anv an ostiz', + 'media_base_url' => 'Chomlec\'h diazez ar mediaoù', + 'media_base_url_hint' => + 'Ma \'z implijit ur CDN pe ur servij diavaez evit muzuliañ heklev, e c\'hellit lakaat anezho amañ.', + 'admin_gateway' => 'Chomlec\'h an daolenn-stur', + 'admin_gateway_hint' => + 'An hent evit mont d\'an daolenn-stur (da sk. https://skouer.bzh/cp-admin). Dre ziouer eo cp-admin, met erbedet oc\'h kemmañ anezhañ evit abegoù a denn d\'an diogelroez.', + 'auth_gateway' => 'Chomlec\'h ar c\'hennaskañ', + 'auth_gateway_hint' => + 'An hent evit mont d\'ar bajenn gennaskañ (da sk. https://skouer.bzh/cp-auth). Dre ziouer eo cp-auth, met erbedet oc\'h kemmañ anezhañ evit abegoù a denn d\'an diogelroez.', + 'database_config' => 'Arventennoù ar stlennvon', + 'database_config_hint' => + 'Castopod a rank bezañ kennesket ouzh ho stlennvon MySQL (pe MariaDB). Mont e darempred gant merour ho tafariad ma n\'emañ ket ganeoc\'h an titouroù-se.', + 'db_hostname' => 'Anv ostiz ar stlennvon', + 'db_name' => 'Anv ar stlennvon (an diaz)', + 'db_username' => 'Anv implijer ar stlennvon', + 'db_password' => 'Ger-tremen ar stlennvon', + 'db_prefix' => 'Rakger an taolennoù', + 'db_prefix_hint' => + "Rakger taolennoù Castopod. Laoskit evel m'emañ ma ne ouzoc'h ket petra a dalv.", + 'cache_config' => 'Arventennoù ar grubuilh (cache)', + 'cache_config_hint' => + 'Dibabit hoc’h ardoer krubuilh muiañ plijet. Laoskit evel m\'emañ ma ne ouzoc\'h ket petra a dalv.', + 'cache_handler' => 'Aorder krubuilh', + 'cacheHandlerOptions' => [ + 'file' => 'Restroù', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'War-lerc\'h', + 'submit' => 'Echuiñ ar staliañ', + 'create_superadmin' => 'Krouit ho kont gourverour·ez (superadmin)', + 'email' => 'Postel', + 'username' => 'Anv implijer·ez', + 'password' => 'Ger-tremen', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ho kont gourverour·ez a zo bet krouet gant berzh. Kevreit ha krogit da bodkastiñ!', + 'databaseConnectError' => + 'N\'en deus ket gellet Castopod kevreañ ouzh ho stlennvon. Kemmit arventennoù ar stlennvon ha klaskit en-dro.', + 'writeError' => + "N'haller ket krouiñ/skrivañ ar restr `.env`. Deoc'h-c'hwi da grouiñ anezhi dre zorn diwar ar patrom `.env.example` az o e pakad Castopod.", + ], +]; diff --git a/modules/Admin/Language/br/Navigation.php b/modules/Admin/Language/br/Navigation.php new file mode 100644 index 00000000..de1da33e --- /dev/null +++ b/modules/Admin/Language/br/Navigation.php @@ -0,0 +1,44 @@ + 'Kuzhat/diskouez ar varrenn gostez', + 'go_to_website' => 'Mont d\'al lec\'hienn', + 'go_to_admin' => 'Mont d\'an daolenn-stur', + 'not-authorized' => 'Difennet', + 'dashboard' => 'Taolenn-stur', + 'admin' => 'Degemer', + 'podcasts' => 'Podkastoù', + 'podcast-list' => 'An holl bodkastoù', + 'podcast-create' => 'Krouiñ ur podkast', + 'all-podcast-imports' => 'An holl bodkastoù enporzhiet', + 'podcast-imports-add' => 'Enporzhiañ ur podkast', + 'persons' => 'Emellerien·ezed', + 'person-list' => 'An holl emellerien·ezed', + 'person-create' => 'Krouiñ un emeller·ez', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Implijerien·ezed stanket', + 'fediverse-blocked-domains' => 'Domanioù stanket', + 'users' => 'Implijerien·ezed', + 'user-list' => 'An holl implijerien·ezed', + 'user-create' => 'Krouiñ un implijer·ez', + 'pages' => 'Pajennoù', + 'page-list' => 'An holl bajennoù', + 'page-create' => 'Krouiñ ur bajenn', + 'settings' => 'Arventennoù', + 'settings-general' => 'Hollek', + 'settings-theme' => 'Neuz', + 'admin-about' => 'A-zivout', + 'account' => [ + 'my-account' => 'Ma c\'hont', + 'change-password' => 'Kemmañ ar ger-tremen', + 'logout' => 'Digennaskañ', + ], +]; diff --git a/modules/Admin/Language/br/Notifications.php b/modules/Admin/Language/br/Notifications.php new file mode 100644 index 00000000..3f2ed5f5 --- /dev/null +++ b/modules/Admin/Language/br/Notifications.php @@ -0,0 +1,19 @@ + 'Kemennoù', + 'reply' => 'Respontet eo bet d\'ho kemennadenn gant {actor_username}', + 'favourite' => 'Ouzhpennet eo bet ho kemennadenn d\'h·e re garetañ gant {actor_username}', + 'reblog' => 'Rannet eo bet ho kemennadenn gant {actor_username}', + 'follow' => 'Krog eo {actor_username} da heuliañ ac\'hanoc\'h', + 'no_notifications' => 'Kemenn ebet', + 'mark_all_as_read' => 'Merkañ pep tra evel lennet', +]; diff --git a/modules/Admin/Language/br/Page.php b/modules/Admin/Language/br/Page.php new file mode 100644 index 00000000..b99aa723 --- /dev/null +++ b/modules/Admin/Language/br/Page.php @@ -0,0 +1,30 @@ + 'Distreiñ d\'ar bennbajennad', + 'page' => 'Pajenn', + 'all_pages' => 'An holl bajennoù', + 'create' => 'Krouiñ ur bajenn', + 'go_to_page' => 'Mont d\'ar bajenn', + 'edit' => 'Kemm ar bajenn', + 'delete' => 'Dilemel ar bajenn', + 'form' => [ + 'title' => 'Titl', + 'permalink' => 'Ere peurzalc\'hus', + 'content' => 'Danvez', + 'submit_create' => 'Krouiñ ar bajenn', + 'submit_edit' => 'Enrollañ', + ], + 'messages' => [ + 'createSuccess' => 'Krouet eo bet ar bajenn "{pageTitle}" gant berzh!', + 'editSuccess' => 'Nevesaet eo bet ar bajenn gant berzh!', + ], +]; diff --git a/modules/Admin/Language/br/Pager.php b/modules/Admin/Language/br/Pager.php new file mode 100644 index 00000000..776905f9 --- /dev/null +++ b/modules/Admin/Language/br/Pager.php @@ -0,0 +1,21 @@ + 'Merdeiñ', + 'first' => 'Kentañ', + 'previous' => 'Kent', + 'next' => 'Da heul', + 'last' => 'Diwezhañ', + 'older' => 'Koshañ', + 'newer' => 'Nevesañ', + 'invalidTemplate' => 'N\'eo ket {0} ur patrom reizh.', + 'invalidPaginationGroup' => 'N\'eo ket {0} ur strollad reizh.', +]; diff --git a/modules/Admin/Language/br/Person.php b/modules/Admin/Language/br/Person.php new file mode 100644 index 00000000..e91d9fcd --- /dev/null +++ b/modules/Admin/Language/br/Person.php @@ -0,0 +1,65 @@ + 'Emellerien·ezed', + 'all_persons' => 'An holl emellerien·ezed', + 'no_person' => 'Emeller·ez ebet !', + 'create' => 'Krouiñ un emeller·ez', + 'view' => 'Gwelet an emeller·ez', + 'edit' => 'Kemmañ an emeller·ez', + 'delete' => 'Dilemel an emeller·ez', + 'messages' => [ + 'createSuccess' => 'Krouet eo bet an emeller·ez gant berzh!', + 'editSuccess' => 'Nevesaet eo bet an emeller·ez gant berzh!', + 'deleteSuccess' => 'Tennet eo bet an emeller·ez!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'An avatar a rankfe bezañ ur c\'harrez ha 400px e vent da nebeutañ.', + 'full_name' => 'Anv klok', + 'full_name_hint' => 'Anv klok pe lesanv an emeller·ez.', + 'unique_name' => 'Anv unel', + 'unique_name_hint' => 'Implijet evit an URLioù', + 'information_url' => 'URL an titouroù', + 'information_url_hint' => + 'Un URL a gas betek titouroù an emeller·ez, evel ur bajenn bersonel pe un aelad war ur savenn all.', + 'submit_create' => 'Krouiñ an emeller·ez', + 'submit_edit' => 'Enrollañ an emeller·ez', + ], + 'podcast_form' => [ + 'title' => 'Merañ an emellerien·ezed', + 'add_section_title' => 'Ouzhpennañ emellerien·ezed d\'ar podkast-mañ', + 'add_section_subtitle' => 'Gallout a rit dibab meur a emeller·ez ha meur a roll.', + 'persons' => 'Emellerien·ezed', + 'persons_hint' => + 'Gallout a rit dibab un emeller·ez pe meur a hini gant ar memes roll. Rankout a reoc\'h krouiñ an emellerien·ezed a-raok avat.', + 'roles' => 'Rolloù', + 'roles_hint' => + 'Gallout a rit dibab roll ebet, unan pe meur hini evit pep emeller·ez.', + 'submit_add' => 'Ouzhpennañ emellerien·ezed', + 'remove' => 'Lemel', + ], + 'episode_form' => [ + 'title' => 'Merañ an emellerien·ezed', + 'add_section_title' => 'Ouzhpennañ emellerien·ezed d\'ar rann-mañ', + 'add_section_subtitle' => 'Gallout a rit dibab meur a emeller·ez ha meur a roll.', + 'persons' => 'Emellerien·ezed', + 'persons_hint' => + 'Gallout a rit dibab un emeller·ez pe meur a hini gant ar memes roll. Rankout a reoc\'h krouiñ an emellerien·ezed a-raok avat.', + 'roles' => 'Rolloù', + 'roles_hint' => + 'Gallout a rit dibab roll ebet, unan pe meur hini evit pep emeller·ez.', + 'submit_add' => 'Ouzhpennañ emellerien·ezed', + 'remove' => 'Lemel', + ], + 'credits' => 'Perzhidi', +]; diff --git a/modules/Admin/Language/br/Platforms.php b/modules/Admin/Language/br/Platforms.php new file mode 100644 index 00000000..959e9f60 --- /dev/null +++ b/modules/Admin/Language/br/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Savennoù podkastoù', + 'social' => 'Rouedadoù sokial', + 'funding' => 'Liammoù arc\'hantaouiñ', + ], + 'website' => 'Lec\'hienn', + 'home_url' => 'Mont da lec\'hienn {platformName}', + 'register' => 'Enskrivañ', + 'submit_url' => 'Kasit ho podkast war {platformName}', + 'your_link' => 'Ho liamm', + 'your_id' => [ + 'podcasting' => 'Hoc’h anaout (ID)', + 'social' => 'Hoc’h anaout (ID)', + 'funding' => 'Ho CTA', + ], + 'your_cta' => 'Ho kalv da ober', + 'visible' => 'Diskouez e pajenn ar podkast?', + 'on_embed' => 'Diskouez el lenner enkorfet?', + 'remove' => 'Dilemel {platformName}', + 'submit' => 'Enrollañ', + 'messages' => [ + 'updateSuccess' => 'Nevesaet eo bet ereoù ar savennoù gant berzh!', + 'removeLinkSuccess' => 'Dilamet eo bet ere ar savenn.', + 'removeLinkError' => + 'N\'eo ket bet dilamet ere ar savenn. Klaskit en-dro.', + ], + 'description' => [ + 'podcasting' => 'ID ar podkast war ar savenn-mañ', + 'social' => 'ID kont ar podkast war ar savenn-mañ', + 'funding' => 'Kemennadenn evit broudañ', + ], +]; diff --git a/modules/Admin/Language/br/Podcast.php b/modules/Admin/Language/br/Podcast.php new file mode 100644 index 00000000..2a754f54 --- /dev/null +++ b/modules/Admin/Language/br/Podcast.php @@ -0,0 +1,337 @@ + 'An holl bodkastoù', + 'no_podcast' => 'N\'eo bet kavet podkast ebet!', + 'create' => 'Krouiñ ur podkast', + 'import' => 'Enporzhiañ ur podkast', + 'all_imports' => 'Ar podkastoù enporzhiet', + 'new_episode' => 'Rann nevez', + 'view' => 'Gwelet ar podkast', + 'edit' => 'Kemmañ ar podkast', + 'publish' => 'Embann ar podkast', + 'publish_edit' => 'Kemmañ an embannadur', + 'delete' => 'Dilemel ar podkast', + 'see_episodes' => 'Gwelet ar rannoù', + 'see_contributors' => 'Gwelet ar berzhidi, ar perzhiadezed', + 'monetization_other' => 'Doare arc\'hantaouiñ all', + 'go_to_page' => 'Gwelet ar bajenn', + 'latest_episodes' => 'Rannoù diwezhañ', + 'see_all_episodes' => 'Gwelet an holl rannoù', + 'draft' => 'Brouilhed', + 'messages' => [ + 'createSuccess' => 'Krouet eo bet ar podkast gant berzh!', + 'editSuccess' => 'Nevesaet eo bet ar podkast gant berzh!', + 'importSuccess' => 'Enporzhiet eo bet ar podkast gant berzh!', + 'deleteSuccess' => 'Dilamet eo bet ar podkast @{podcast_handle} gant berzh!', + 'deletePodcastMediaError' => 'C\'hwitadenn war dilemel {type, select, + cover {golo} + banner {giton} + other {media} + } ar podkast.', + 'deleteEpisodeMediaError' => 'C\'hwitadenn war dilemel {type, select, + transcript {treuzskrivadur} + chapters {chabistroù} + image {golo} + audio {aodio} + other {media} + } ar rann {episode_slug}.', + 'deletePodcastMediaFolderError' => 'C\'hwitadenn war dilemel teuliad ar mediaioù {folder_path}. Gallout a rit lemel an teuliad-mañ diouzh ar gantenn dre zorn.', + 'podcastFeedUpdateSuccess' => 'Nevesadenn: {number_of_new_episodes, plural, + one {# rann} + two {# rann} + few {# rann} + many {# rann} + other {# rann} + } a zo bet ouzhpennet d\'ar podkast gant berzh!', + 'podcastFeedUpToDate' => 'Nevesaet eo bet ar podkast dija.', + 'publishError' => 'Ar podkast-mañ a zo bet embannet dija pe steuñvet eo e embannadur.', + 'publishEditError' => 'N\'eo ket steuñvet embannadur ar podkast-mañ.', + 'publishCancelSuccess' => 'Nullet eo bet embannadur ar podkast gant berzh!', + 'scheduleDateError' => 'Ret eo lakaat un deiziad evit an embannadur!', + ], + 'form' => [ + 'identity_section_title' => 'Titouroù diwar-benn ar podkast', + 'identity_section_subtitle' => 'Ar maeziennoù a laka ac\'hanoc\'h da vezañ remerket.', + 'fediverse_section_title' => 'Identelezh er Fediverse', + + 'cover' => 'Golo ar podkast', + 'cover_size_hint' => 'Ar golo a rankfe bezañ ur c\'harrez ha 1400px e vent da nebeutañ.', + 'banner' => 'Giton ar podkast', + 'banner_size_hint' => 'Ar giton a rankfe bezañ 3:1 e feur led/sav ha bezañ 1500px e led d\'an nebeutañ.', + 'banner_delete' => 'Dilemel giton ar podkast', + 'title' => 'Titl', + 'handle' => 'Anv ar podkast (handle)', + 'handle_hint' => + 'Implijet evit anavezout ar podkast. Lizherennoù bras pe munut, niveroù hag islinenn (_) degemeret.', + 'type' => [ + 'label' => 'Doare', + 'episodic' => 'Bep ur mare', + 'episodic_hint' => 'M\'eo ar rannoù da vezañ selaouet hep urzh resis. Ar rannoù nevesoc’h a vo kinniget da gentañ.', + 'serial' => 'Heuliad', + 'serial_hint' => 'M\'eo ar rannoù da vezañ selaouet gant un urzh resis. Ar rannoù a vo kinniget hervez urzh an niverennoù.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Ar medium evel ma vez kinniget gant ar valizenn RSS podcast:medium. Cheñch an dra-se a c\'hell cheñch an doare ma vo kinniget ho kwazh gant al lennerien.', + 'podcast' => 'Podkast', + 'podcast_hint' => 'Evit deskrivañ gwazh ur podkast.', + 'music' => 'Sonerezh', + 'music_hint' => 'Ur wazh gant sonerezh aozet e-barzh un "album". Pep item zo un ton en album.', + 'audiobook' => 'Levr klevet', + 'audiobook_hint' => 'Ur seurt aodio dibar gant un item dre wazh, peotramant pa glot an itemoù gant chabistroù al levr.', + ], + 'description' => 'Deskrivadur', + 'classification_section_title' => 'Rummatadur', + 'classification_section_subtitle' => + 'Ar maeziennoù-mañ o do ul levezon war an niver a selaouerien·ezed hag ho kevezerezh.', + 'language' => 'Yezh', + 'category' => 'Rummad', + 'category_placeholder' => 'Dibab ur rummad…', + 'other_categories' => 'Rummadoù all', + 'parental_advisory' => [ + 'label' => 'Kemenn evit ar gerent', + 'hint' => 'Hag an dra-se a zo danvez ha ne zlefe ket gwelet gant bugale?', + 'undefined' => 'andermenet', + 'clean' => 'Dereat', + 'explicit' => 'Danvez evit an oadourien', + ], + 'author_section_title' => 'Aozer·ez', + 'author_section_subtitle' => 'Piv zo o verañ ar podkast?', + 'owner_name' => 'Anv ar perc\'henn·ez', + 'owner_name_hint' => + 'Evit a sell ouzh ar mererezh. War ar wazh RSS publik e vo.', + 'owner_email' => 'Chomlec\'h postel ar perc\'henn·ez', + 'owner_email_hint' => + 'Implijet e vo gant an darn vrasañ eus ar savennoù evit gwiriañ perc\'hentiezh ar podkast. War ar wazh RSS publik e vo.', + 'is_owner_email_removed_from_feed' => 'Lemel chomlec\'h postel ar perc\'henn·ez diouzh ar wazh RSS publik', + 'is_owner_email_removed_from_feed_hint' => 'Rankout a rafec\'h lakaat ar chomlec\'h war wel adarre, evit ur mare, evit ma vefe gouest ur meneger da wiriañ oc\'h ar perc\'henn·ez.', + 'publisher' => 'Embanner·ez', + 'publisher_hint' => + 'Ar strollad kiriek eus sevel ar podkast. Alies eo embregerezh pe rouedad ar podkast. A-wechoù e vez anvet ar vaezienn-mañ "Aozer·ez".', + 'copyright' => 'Gwirioù an aozer·ez', + 'location_section_title' => 'Lec\'h', + 'location_section_subtitle' => 'Eus peseurt lec\'h ez eus kaoz er podkast-mañ?', + 'location_name' => 'Anv pe chomlec\'h al lec\'h', + 'location_name_hint' => 'Gallout a ra bezañ gwir pe faltaziek', + 'monetization_section_title' => 'Moneisaat', + 'monetization_section_subtitle' => + 'Dastum arc\'hant a-drugarez d\'ho selaouerien·ezed.', + 'premium' => 'Premium', + 'premium_by_default' => 'Ar rannoù a zo evit ar re bremium dre ziouer', + 'premium_by_default_hint' => 'Rannoù ar podkast a vo merket Premium dre ziouer. Gallout a rit lakaat rannoù zo evel publik.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Mont da welet ho taolenn-stur OP3 (liamm diavaez)', + 'op3_hint' => 'Talvoudekait ho roadennoù gant OP3, zo ur servij open source diavaez evit dielfennañ ar muzulioù heklev. Rannit, kadarnait ha lakait ho roadennoù keñver-ha-keñver gant re ekosistem ar podkastoù digor.', + 'op3_enable' => 'Gweredekaat ar servij dielfennañ OP3', + 'op3_enable_hint' => 'Evit abegoù surentez ne vo ket rannet roadennoù ar rannoù Premium gant OP3.', + 'payment_pointer' => 'Chomlec\'h paeañ (Payment Poienter) evit Web Monetization', + 'payment_pointer_hint' => + 'Ar chomlec\'h ma vo dastumet an arc\'hant ganeoc\'h a-drugarez da Web Monetization', + 'advanced_section_title' => 'Arventennoù kempleshoc\'h', + 'advanced_section_subtitle' => + 'M\'ho peus ezhomm eus balizennoù RSS ha n\'eus ket anezho e Castopod e c\'hellit o lakaat amañ.', + 'custom_rss' => 'Balizennoù RSS personelaet evit ar podkast', + 'custom_rss_hint' => 'An dra-se a vo ouzhpennet e-barzh ar valizenn ❬channel❭.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'URL nevez ar wazh', + 'new_feed_url_hint' => 'Implijit ar vaezienn-mañ pa cheñchit anv domani pe savenn herberc\'hiañ ho podkast. M\'eo enporzhiet ar podkast e vez lakaet enni URL a-vremañ ar wazh dre ziouer.', + 'old_feed_url' => 'URL kozh ar wazh', + 'partnership' => 'Kevelerezh', + 'partner_id' => 'ID', + 'partner_link_url' => 'Ere URL', + 'partner_image_url' => 'URL ar skeudenn', + 'partner_id_hint' => 'Hoc’h ID deoc\'h-c\'hwi e ti ar c\'heveler', + 'partner_link_url_hint' => 'Chomlec\'h generek an ereoù gant ar c\'heveler', + 'partner_image_url_hint' => 'Chomlec\'h generek ar skeudennoù gant ar c\'heveler', + 'block' => 'Ar podkast a rankfe bezañ kuzhet diouzh ar rolladoù publik', + 'block_hint' => + 'Diskouez pe kuzhat ar podkast: trec\'haoliñ an afell-mañ a viro ar podkast a-bezh ouzh bezañ diskouezet war Apple Podcasts, Google Podcasts pe savennoù all hag a implij ar renabloù-se. (N\'eus gwarant ebet)', + 'complete' => 'Ne vo mui rannoù nevez gant ar podkast', + 'lock' => 'Mirout ar podkast ouzh bezañ eilet', + 'lock_hint' => + 'Ar pal eo lavaret d\'ar savennoù all hag aotreet int da enporzhiañ ar wazh-mañ pe get. "Ya" a dalv eo nac\'het an holl c\'houlennoù enporzhiañ.', + 'submit_create' => 'Krouiñ ar podkast', + 'submit_edit' => 'Enrollañ ar podkast', + ], + 'category_options' => [ + 'uncategorized' => 'hep rummad', + 'arts' => 'Arzoù', + 'business' => 'Embregerezh', + 'comedy' => 'Fentc\'hoari', + 'education' => 'Deskadurezh', + 'fiction' => 'Faltazi', + 'government' => 'Gouarnamant', + 'health_and_fitness' => 'Yec\'hed ha fitness', + 'history' => 'Istor', + 'kids_and_family' => 'Bugale ha familh', + 'leisure' => 'Dudi', + 'music' => 'Sonerezh', + 'news' => 'Keleier', + 'religion_and_spirituality' => 'Relijion ha speredelezh', + 'science' => 'Skiant', + 'society_and_culture' => 'Kevredigezh ha sevenadur', + 'sports' => 'Sportoù', + 'technology' => 'Teknologiezh', + 'true_crime' => 'Teulioù an torfed', + 'tv_and_film' => 'Skinwel ha filmoù', + 'books' => 'Levrioù', + 'design' => 'Ergrafañ', + 'fashion_and_beauty' => 'Giz ha kened', + 'food' => 'Boued', + 'performing_arts' => 'Arzoù an arvest', + 'visual_arts' => 'Arzoù ar gweled', + 'careers' => 'Respetoù', + 'entrepreneurship' => 'Antreprenerezh', + 'investing' => 'Postadur', + 'management' => 'Mererezh', + 'marketing' => 'Marketing', + 'non_profit' => 'Hep pal kenwerzhel', + 'comedy_interviews' => 'Atersadennoù fentus', + 'improv' => 'Primaozañ', + 'stand_up' => 'Stand up', + 'courses' => 'Kentelioù', + 'how_to' => 'Tutorial', + 'language_learning' => 'Deskiñ yezhoù', + 'self_improvement' => 'Diorren hiniennel', + 'comedy_fiction' => 'Fentc\'hoari faltaziek', + 'drama' => 'Drama', + 'science_fiction' => 'Skiant-faltazi', + 'alternative_health' => 'Yec\'hed all', + 'fitness' => 'Fitness', + 'medicine' => 'Medisinerezh', + 'mental_health' => 'Yec\'hed-spered', + 'nutrition' => 'Magadurezh', + 'sexuality' => 'Seksualegezh', + 'education_for_kids' => 'Deskadurezh evit ar vugale', + 'parenting' => 'Kerentelezh', + 'pets_and_animals' => 'Loened-ti ha loened', + 'stories_for_kids' => 'Marvailhoù evit ar vugale', + 'animation_and_manga' => 'Tresadennoù bev ha Manga', + 'automotive' => 'Kirri-tan', + 'aviation' => 'Kirri-nij', + 'crafts' => 'Artizanerezh', + 'games' => 'C\'hoarioù', + 'hobbies' => 'Dudioù', + 'home_and_garden' => 'Ti ha jardin', + 'video_games' => 'C\'hoarioù video', + 'music_commentary' => 'Evezhiadenn sonerezh', + 'music_history' => 'Istor ar sonerezh', + 'music_interviews' => 'Atersadennoù sonerezh', + 'business_news' => 'Keleier ekonomikel', + 'daily_news' => 'Keleier pemdeziek', + 'entertainment_news' => 'Keleier an diduamant', + 'news_commentary' => 'Evezhiadenn ar c\'heleier', + 'politics' => 'Politikerezh', + 'sports_news' => 'Keleier sport', + 'tech_news' => 'Keleier teknologiezh', + 'buddhism' => 'Boudaegezh', + 'christianity' => 'Kristeniezh', + 'hinduism' => 'Hindouegezh', + 'islam' => 'Islam', + 'judaism' => 'Yuzevegezh', + 'religion' => 'Relijion', + 'spirituality' => 'Speredelezh', + 'astronomy' => 'Steredoniezh', + 'chemistry' => 'Kimiezh', + 'earth_sciences' => 'Skiantoù an douar', + 'life_sciences' => 'Bevoniezh', + 'mathematics' => 'Matematikoù', + 'natural_sciences' => 'Skiantoù an natur', + 'nature' => 'Natur', + 'physics' => 'Fizik', + 'social_sciences' => 'Skiantoù sokial', + 'documentary' => 'Teulioù', + 'personal_journals' => 'Deizlevr hiniennel', + 'philosophy' => 'Prederouriezh', + 'places_and_travel' => 'Lec\'hioù ha beajoù', + 'relationships' => 'Darempredoù', + 'baseball' => 'Baseball', + 'basketball' => 'Basket-ball', + 'cricket' => 'Kriked', + 'fantasy_sports' => 'Sportoù faltaziek', + 'football' => 'Mell-droad', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugbi', + 'running' => 'Redek', + 'soccer' => 'Mell-droad', + 'swimming' => 'Neuierezh', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Natur', + 'wrestling' => 'Gouren', + 'after_shows' => 'Goude abadenn', + 'film_history' => 'Istor ar sinema', + 'film_interviews' => 'Atersadennoù er sinema', + 'film_reviews' => 'Barnadennoù filmoù', + 'tv_reviews' => 'Barnadennoù tele', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Distreiñ da daolenn-stur ar podkast', + 'post' => 'Ho kemennadenn vrudañ', + 'post_hint' => + "Skrivit ur gemennadenn evit kemenn embannadur ho podkast. War bajenn degemer ho podkast e vo diskouezet ar gemennadenn.", + 'message_placeholder' => 'Skrivit ho kemennadenn…', + 'submit' => 'Embann', + 'publication_date' => 'Deiziad an embann', + 'publication_method' => [ + 'now' => 'Bremañ', + 'schedule' => 'Steuñviñ', + ], + 'scheduled_publication_date' => 'Deiziad embannadur steuñvet', + 'scheduled_publication_date_hint' => + 'Gallout a rit steuñviñ embannadur ar podkast en ur choaz un deiziad evit an embannadur. Dleout a ra ar vaezienn bezañ er furmad YYYY-MM-DD HH:mm', + 'submit_edit' => 'Kemmañ an embannadur', + 'cancel_publication' => 'Nullañ an embann', + 'message_warning' => 'N\'ho peus ket skrivet ur gemennadenn evit brudañ ho rann !', + 'message_warning_hint' => 'Ouzhpennañ ur gemennadenn a lakay muioc\'h a dud er jeu, ha diwar se e vo gwelet muioc\'h ho podkast.', + 'message_warning_submit' => 'Embann memestra', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'mod brouilhed', + 'not_published' => 'N\'eo ket embannet ar podkast-mañ c\'hoazh.', + 'scheduled' => 'Ar podkast-mañ a vo embannet d\'an/d\'ar {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Pa vo dilamet ar podkast e vo dilamet an holl rannoù, restroù media, kemennadennoù ha stadegoù liammet outañ. Ur wech dilamet, ne c'hell bezañ adtapet an traoù.", + 'understand' => 'Kompren a ran, c\'hoant am eus da zilemel ar podkast da vat', + 'submit' => 'Dilemel', + ], + 'by' => 'Gant {publisher}', + 'season' => 'Koulzad {seasonNumber}', + 'list_of_episodes_year' => 'Rannoù {year} ({episodeCount})', + 'list_of_episodes_season' => + 'Rannoù ar c\'houlzad {seasonNumber} ({episodeCount})', + 'no_episode' => 'N\'eus bet kavet rann ebet !', + 'follow' => 'Heuliañ', + 'followers' => '{numberOfFollowers, plural, + one {# heulier·ez} + two {# heulier·ez} + other {# heulier·ez} + }', + 'posts' => '{numberOfPosts, plural, + one {# gemennadenn} + two {# gemennadenn} + few {# c\'hemennadenn} + many {a gemennadennoù} + other {# kemennadenn} + }', + 'activity' => 'Oberiantiz', + 'episodes' => 'Rannoù', + 'sponsor' => 'Harpit ac\'hanomp', + 'funding_links' => 'Ereoù evit arc\'hantaouiñ {podcastTitle}', + 'find_on' => 'Kavit {podcastTitle} war', + 'listen_on' => 'Selaouit war', +]; diff --git a/modules/Admin/Language/br/PodcastNavigation.php b/modules/Admin/Language/br/PodcastNavigation.php new file mode 100644 index 00000000..f3d2a8e6 --- /dev/null +++ b/modules/Admin/Language/br/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Mont da pajenn ar podkast', + 'rss_feed' => 'Gwazh RSS', + 'dashboard' => 'Taolenn-stur ar podkast', + 'podcast-view' => 'Degemer', + 'podcast-edit' => 'Kemmañ ar podkast', + 'podcast-persons-manage' => 'Merañ an emellerien·ezed', + 'podcast-imports' => 'Ar podkastoù enporzhiet', + 'podcast-imports-sync' => 'Sinkronaat ar gwazhoù', + 'episodes' => 'Rannoù', + 'episode-list' => 'An holl rannoù', + 'episode-create' => 'Rann nevez', + 'analytics' => 'Muzulioù heklev', + 'podcast-analytics' => 'Gwel a-vras', + 'podcast-analytics-webpages' => 'Gweladennoù ar pajennoù web', + 'podcast-analytics-locations' => 'Lec\'hioù', + 'podcast-analytics-unique-listeners' => 'Selaouerien·ezed unel', + 'podcast-analytics-players' => 'Lennerioù', + 'podcast-analytics-listening-time' => 'Padelezh ar selaou', + 'podcast-analytics-time-periods' => 'Mareoù ar selaou', + 'monetization' => 'Moneisaat', + 'subscription-list' => 'An holl goumanantoù', + 'subscription-create' => 'Ouzhpennañ ur c\'houmanant', + 'contributors' => 'Perzhidi, perzhiadezed', + 'contributor-list' => 'An holl berzhidi ha perzhiadezed', + 'contributor-add' => 'Ouzhpennañ ur perzhiad pe ur berzhiadez', + 'broadcast' => 'Skignañ', + 'platforms-podcasting' => 'Arloadoù podkastoù', + 'platforms-social' => 'Rouedadoù sokial', + 'platforms-funding' => 'Liammoù arc\'hantaouiñ', + 'podcast-monetization-other' => 'Un dra all', +]; diff --git a/modules/Admin/Language/br/Settings.php b/modules/Admin/Language/br/Settings.php new file mode 100644 index 00000000..62dab9f1 --- /dev/null +++ b/modules/Admin/Language/br/Settings.php @@ -0,0 +1,58 @@ + 'Arventennoù hollek', + 'instance' => [ + 'title' => 'Istañs', + 'site_icon' => 'Arlun al lec\'hienn', + 'site_icon_delete' => 'Dilemel arlun al lec\'hienn', + 'site_icon_hint' => 'Arlunioù al lec\'hienn zo ar pezh a welit war ivinelloù ho merdeer, barrenn ar pennrolloù, ha pa vez ouzhpennet al lec\'hienn d\'ur pellgomzer evel ur verradenn.', + 'site_icon_helper' => 'An arlun a rankfe bezañ ur c\'harrez ha 512px e vent da nebeutañ.', + 'site_name' => 'Titl al lec\'hienn', + 'site_description' => 'Deskrivadur al lec\'hienn', + 'submit' => 'Enrollañ', + 'editSuccess' => 'Nevesaet eo bet an istañs gant berzh!', + 'deleteIconSuccess' => 'Skarzhet eo bet arlun al lec\'hienn gant berzh!', + ], + 'images' => [ + 'title' => 'Skeudennoù', + 'subtitle' => 'Amañ e c\'hellit azgenel an holl skeudennoù diwar ar skeudennoù orin a oa bet karget. Da vezañ implijet ma kav deoc\'h e vank skeudennoù zo. Hir a-walc\'h e c\'hell bezañ al labour-mañ.', + 'regenerate' => 'Azgenel ar skeudennoù', + 'regenerationSuccess' => 'An holl skeudennoù zo bet azganet gant berzh!', + ], + 'housekeeping' => [ + 'title' => 'Kempenn an istañs', + 'subtitle' => 'Lañsañ labourioù a bep seurt evit kempenn an istañs. Da vezañ implijet ma welit kudennoù gant restroù media pe aterinder ar roadennoù. Hir a-walc\'h e c\'hell bezañ al labourioù-mañ.', + 'reset_counts' => 'Adderaouekaat ar c\'honterioù', + 'reset_counts_helper' => 'Gant an dibarzh-mañ e vo adjedet hag adderaouekaet ar c\'hontoù (niver a heulierien·ezed, a bostoù, a evezhiadennoù, …).', + 'rewrite_media' => 'Adskrivañ metaroadennoù ar media', + 'rewrite_media_helper' => 'Gant an dibarzh-mañ e vo skarzhet ar restroù media diezhomm hag adkrouet en-dro (skeudennoù, restroù aodio, treuzskrivadurioù, chabistroù, …)', + 'rename_episodes_files' => 'Adenvel restroù aodio ar rannoù', + 'rename_episodes_files_hint' => 'Gant an dibarzh-mañ e vo adanvet restroù aodio an holl rannoù gant ur chadenn arouezennoù dre zegouezh. Da implijout m\'eo bet kavet unan eus liammoù ho rannoù prevez, rak an dra-se a guzho anezhañ en-dro.', + 'clear_cache' => 'Naetaat ar grubuilh', + 'clear_cache_helper' => 'Gant an dibarzh-mañ e vo naetaet krubuilh Redis pe restroù an teuliad writable/cache.', + 'run' => 'Lañsañ ar c\'hempenn', + 'runSuccess' => 'Echu eo ar c\'hempenn gant berzh!', + ], + 'theme' => [ + 'title' => 'Neuz', + 'accent_section_title' => 'Liv kentañ', + 'accent_section_subtitle' => 'Choazit al liv a roio an neuz d\'an holl bajennoù publik.', + 'pine' => 'Pin', + 'crimson' => 'Ruz-mouk', + 'amber' => 'Goularz', + 'lake' => 'Lenn', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Enrollañ', + 'setInstanceThemeSuccess' => 'Cheñchet eo bet an neuz gant berzh!', + ], +]; diff --git a/modules/Admin/Language/br/Soundbite.php b/modules/Admin/Language/br/Soundbite.php new file mode 100644 index 00000000..85d3ce58 --- /dev/null +++ b/modules/Admin/Language/br/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Tennadoù son', + 'soundbite' => 'Tennad son', + ], + 'messages' => [ + 'createSuccess' => 'Krouet eo bet an tennad son gant berzh!', + 'deleteSuccess' => 'Dilamet eo bet an tennad son gant berzh!', + ], + 'form' => [ + 'title' => 'Tennad son nevez', + 'soundbite_title' => 'Titl an tennad son', + 'start_time' => 'Kregiñ da', + 'duration' => 'Padelezh', + 'submit' => 'Krouiñ an tennad son', + ], + 'play' => 'Lenn an tennad son', + 'stop' => 'Paouez an tennad son', + 'create' => 'Tennad son nevez', + 'delete' => 'Dilemel an tennad son', +]; diff --git a/modules/Admin/Language/br/Validation.php b/modules/Admin/Language/br/Validation.php new file mode 100644 index 00000000..59c49e93 --- /dev/null +++ b/modules/Admin/Language/br/Validation.php @@ -0,0 +1,17 @@ + + '{field} n\'eo ket ur skeudenn, peotrament n\'eo ket ledan a-walc\'h pe uhel a-walc\'h.', + 'is_image_ratio' => + '{field} n\'eo ket ur skeudenn, peotrament n\'eo ket mat ar ratio.', + 'is_json' => 'JSON direizh a zo e-barzh {field}.', +]; diff --git a/modules/Admin/Language/br/VideoClip.php b/modules/Admin/Language/br/VideoClip.php new file mode 100644 index 00000000..1ce237b3 --- /dev/null +++ b/modules/Admin/Language/br/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Klipoù video', + 'status' => [ + 'label' => 'Statud', + 'queued' => 'el lost', + 'queued_hint' => 'Emañ ar c\'hlip video el lost.', + 'pending' => 'o c\'hortoz', + 'pending_hint' => 'Ganet e vo ar c\'hlip a-benn nebeut.', + 'running' => 'war ar stern', + 'running_hint' => 'Emañ ar c\'hlip o vezañ ganet.', + 'failed' => 'c\'hwitet', + 'failed_hint' => 'Ar c\'hlip n\'eo ket bet ganet: fazi skript.', + 'passed' => 'berzh', + 'passed_hint' => 'Ganet eo bet ar c\'hlip gant berzh!', + ], + 'clip' => 'Klip', + 'duration' => 'Padelezh al labour', + ], + 'title' => 'Klip video: {videoClipLabel}', + 'download_clip' => 'Pellgargañ ar c\'hlip', + 'create' => 'Klip video nevez', + 'go_to_page' => 'Mont da pajenn ar c\'hlip', + 'retry' => 'Klask genel ar c\'hlip en-dro', + 'delete' => 'Dilemel ar c\'hlip', + 'logs' => 'Roll istor al labourioù', + 'messages' => [ + 'alreadyExistingError' => 'Bez ez eus eus ur c\'hlip video heñvel-mik dija!', + 'addToQueueSuccess' => 'Ouzhpennet eo bet ar c\'hlip video d\'al lost, o c\'hortoz e vefe krouet!', + 'deleteSuccess' => 'Dilamet eo bet ar c\'hlip video gant berzh!', + ], + 'format' => [ + 'landscape' => 'A-led', + 'portrait' => 'A-blom', + 'squared' => 'Karrezek', + ], + 'form' => [ + 'title' => 'Klip video nevez', + 'params_section_title' => 'Arventennoù ar c\'hlip video', + 'clip_title' => 'Titl ar c\'hlip', + 'format' => [ + 'label' => 'Choazit ur furmad', + 'landscape_hint' => 'Videoioù a-led gant ur ratio 16:9 a zo dispar evit PeerTube, Youtube ha Vimeo.', + 'portrait_hint' => 'Videoioù a-blom gant ur ratio 9:16 a zo dispar evit TikTok, Youtube shorts ha stories Instagram.', + 'squared_hint' => 'Videoioù karrezek gant ur ratio 1:1 a zo dispar evit Mastodon, Facebook, Twitter ha LinkedIn.', + ], + 'theme' => 'Dibab un neuz', + 'start_time' => 'Kregiñ da', + 'duration' => 'Padelezh', + 'trim_start' => 'Krennañ ar penn-kentañ', + 'trim_end' => 'Krennañ an dibenn', + 'submit' => 'Krouiñ ur c\'hlip video', + ], + 'requirements' => [ + 'title' => 'Mankout a ra binvioù', + 'missing' => 'Mankout a ra ostilhoù. Bezit sur eo bet ouzhpennet an holl vinvioù ez ezhomm anezho evit bezañ gouest da sevel ur video diwar ar rann-mañ!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Levraoueg Freetype evit GD', + 'transcript' => 'Restr an treuzskrivadur (.srt)', + ], +]; diff --git a/modules/Admin/Language/ca/AboutCastopod.php b/modules/Admin/Language/ca/AboutCastopod.php new file mode 100644 index 00000000..c8598e13 --- /dev/null +++ b/modules/Admin/Language/ca/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Sobre Castopod', + 'host_name' => 'Nom del servidor', + 'version' => 'Versió de Castopod', + 'php_version' => 'Versió de PHP', + 'os' => 'Sistema operatiu', + 'languages' => 'Idiomes', + 'update_database' => 'Actualitza la base de dades', + 'messages' => [ + 'databaseUpdateSuccess' => 'La base de dades està actualitzada!', + ], +]; diff --git a/modules/Admin/Language/ca/Breadcrumb.php b/modules/Admin/Language/ca/Breadcrumb.php new file mode 100644 index 00000000..8beefd66 --- /dev/null +++ b/modules/Admin/Language/ca/Breadcrumb.php @@ -0,0 +1,57 @@ + 'Ruta de navegació', + config('Admin') + ->gateway => 'Inici', + 'podcasts' => 'podcasts', + 'episodes' => 'episodis', + 'subscriptions' => 'subscripcions', + 'contributors' => 'col·laboradors', + 'pages' => 'pàgines', + 'settings' => 'preferències', + 'theme' => 'tema', + 'about' => 'quant a', + 'add' => 'afegir', + 'new' => 'nova', + 'edit' => 'editar', + 'persons' => 'persones', + 'publish' => 'publicar', + 'publish-edit' => 'editar la publicació', + 'publish-date-edit' => 'edita la data de publicació', + 'unpublish' => 'desfer la publicació', + 'delete' => 'eliminar', + 'remove' => 'suprimeix', + 'fediverse' => 'Fediverse', + 'blocked-actors' => 'comptes bloquejats', + 'blocked-domains' => 'dominis bloquejats', + 'users' => 'usuaris', + 'my-account' => 'el meu compte', + 'change-password' => 'canviar la contrasenya', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'plataformes', + 'social' => 'xarxes socials', + 'funding' => 'financiació', + 'monetization-other' => 'other monetization', + 'analytics' => 'estadístiques', + 'locations' => 'ubicacions', + 'webpages' => 'pàgines web', + 'unique-listeners' => 'oients únics', + 'players' => 'reproductors', + 'listening-time' => 'temps d\'escolta', + 'time-periods' => 'períodes de temps', + 'soundbites' => 'fragments d\'àudio', + 'video-clips' => 'vídeoclips', + 'embed' => 'reproductor incrustable', + 'notifications' => 'notificacions', + 'suspend' => 'suspèn', +]; diff --git a/modules/Admin/Language/ca/Charts.php b/modules/Admin/Language/ca/Charts.php new file mode 100644 index 00000000..b1085117 --- /dev/null +++ b/modules/Admin/Language/ca/Charts.php @@ -0,0 +1,41 @@ + 'Baixades d\'episodis per servei (durant la setmana passada)', + 'by_player_weekly' => 'Baixades d\'episodis per reproductor (durant la setmana passada)', + 'by_player_yearly' => 'Baixades d\'episodis per reproductor (durant l\'any passat)', + 'by_device_weekly' => 'Baixades d\'episodis per dispositiu (durant la setmana passada)', + 'by_os_weekly' => 'Baixades d\'episodis per sistema operatiu (durant la setmana passada)', + 'podcast_by_region' => 'Baixades d\'episodis per regió (durant la setmana passada)', + 'unique_daily_listeners' => 'Oients únics diaris', + 'unique_monthly_listeners' => 'Oients únics mensuals', + 'by_browser' => 'Pàgines vistes per navegador (durant la setmana passada)', + 'podcast_by_day' => 'Baixades diàries d\'episodis', + 'podcast_by_month' => 'Baixades mensuals d\'episodis', + 'episode_by_day' => 'Baixades diàries d\'episodi (primers 60 dies)', + 'episode_by_month' => 'Baixades mensuals d\'episodis', + 'episodes_by_day' => + 'Baixades dels 5 darrers episodis (durant els seus primers 60 dies)', + 'by_country_weekly' => 'Baixades d\'episodis per país (durant la setmana passada)', + 'by_country_yearly' => 'Baixades d\'episodis per país (durant l\'any passat)', + 'by_domain_weekly' => 'Pàgines vistes per origen (durant la setmana passada)', + 'by_domain_yearly' => 'Pàgines vistes per origen (durant l\'any passat)', + 'by_entry_page' => 'Pàgines vistes per pàgina d\'arribada (durant la setmana passada)', + 'podcast_bots' => 'Bots (exploradors)', + 'daily_listening_time' => 'Temps acumulat d\'escolta diària', + 'monthly_listening_time' => 'Temps acumulat d\'escolta mensual', + 'by_weekday' => 'Per dia de la setmana (darrers 60 dies) ', + 'by_hour' => 'Per hora del dia (darrers 60 dies)', + 'podcast_by_bandwidth' => 'Ample de banda emprat diàriament (en MB)', + 'total_storage_by_month' => 'Emmagatzematge mensual (en MB)', + 'total_bandwidth_by_month' => 'Ample de banda emprat mensualment (en MB)', + 'total_bandwidth_by_month_limit' => 'Limitat a {totalBandwidth} al mes', +]; diff --git a/modules/Admin/Language/ca/Common.php b/modules/Admin/Language/ca/Common.php new file mode 100644 index 00000000..8ce267d5 --- /dev/null +++ b/modules/Admin/Language/ca/Common.php @@ -0,0 +1,52 @@ + 'Sí', + 'no' => 'No', + 'cancel' => 'Cancel·lar', + 'optional' => 'Opcional', + 'more' => 'Més', + 'no_data' => 'No s\'han trobat dades.', + 'close' => 'Tancar', + 'edit' => 'Editar', + 'copy' => 'Copiar', + 'copied' => 'Copiat.', + 'home' => 'Inici', + 'explicit' => 'Explícit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Accions', + 'pageInfo' => 'Pàgina {currentPage} de {pageCount}', + 'go_back' => 'Tornar enrere', + 'forms' => [ + 'editor' => [ + 'write' => 'Escriure', + 'preview' => 'Vista prèvia', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Premeu per seleccionar', + 'loadingText' => 'S\'està carregant…', + 'noResultsText' => 'No s\'han trobat resultats.', + 'noChoicesText' => 'No hi ha opcions per triar', + 'maxItemText' => 'No es poden afegir més elements', + ], + 'upload_file' => 'Pujar un fitxer', + 'remote_url' => 'URL remota', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Reproduir', + 'playing' => 'S\'està reproduint', + ], + 'size_limit' => 'Límit de mida: {0}.', + 'choose_interact' => 'Escolliu com interactuar', + 'view' => 'Vista', +]; diff --git a/modules/Admin/Language/ca/Countries.php b/modules/Admin/Language/ca/Countries.php new file mode 100644 index 00000000..4636231f --- /dev/null +++ b/modules/Admin/Language/ca/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emirats Àrabs Units', + 'AF' => 'Afganistan', + 'AG' => 'Antigua i Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albània', + 'AM' => 'Armènia', + 'AO' => 'Angola', + 'AQ' => 'Antàrtida', + 'AR' => 'Argentina', + 'AS' => 'Samoa Americana', + 'AT' => 'Àustria', + 'AU' => 'Austràlia', + 'AW' => 'Aruba', + 'AX' => 'Illes Åland', + 'AZ' => 'Azerbaidjan', + 'BA' => 'Bòsnia i Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Bèlgica', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgària', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benín', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermudes', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolívia', + 'BQ' => 'Bonaire, Saint Eustatius i Saba', + 'BR' => 'Brasil', + 'BS' => 'Bahames', + 'BT' => 'Bhutan', + 'BV' => 'Illa Bouvet', + 'BW' => 'Botswana', + 'BY' => 'Bielorússia', + 'BZ' => 'Belize', + 'CA' => 'Canadà', + 'CC' => 'Illes Cocos (Keeling)', + 'CD' => 'Congo, República Democràtica del', + 'CF' => 'República Centreafricana', + 'CG' => 'Congo', + 'CH' => 'Suïssa', + 'CI' => "Costa d'Ivori", + 'CK' => 'Illes Cook', + 'CL' => 'Xile', + 'CM' => 'Camerun', + 'CN' => 'Xina', + 'CO' => 'Colòmbia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cap Verd', + 'CW' => 'Curaçao', + 'CX' => 'Illa Christmas', + 'CY' => 'Xipre', + 'CZ' => 'República Txeca', + 'DE' => 'Alemanya', + 'DJ' => 'Djibouti', + 'DK' => 'Dinamarca', + 'DM' => 'Dominica', + 'DO' => 'República Dominicana', + 'DZ' => 'Algèria', + 'EC' => 'Equador', + 'EE' => 'Estònia', + 'EG' => 'Egipte', + 'EH' => 'Sàhara Occidental', + 'ER' => 'Eritrea', + 'ES' => 'Espanya', + 'ET' => 'Etiòpia', + 'FI' => 'Finlàndia', + 'FJ' => 'Illes Fiji', + 'FK' => 'Illes Malvines (Falkland)', + 'FM' => 'Micronèsia, Estats Federats de', + 'FO' => 'Illes Fèroe', + 'FR' => 'França', + 'GA' => 'Gabon', + 'GB' => 'Regne Unit', + 'GD' => 'Granada', + 'GE' => 'Geòrgia', + 'GF' => 'Guaiana Francesa', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenlàndia', + 'GM' => 'Gàmbia', + 'GN' => 'Guinea', + 'GP' => 'Guadalupe', + 'GQ' => 'Guinea Equatorial', + 'GR' => 'Grècia', + 'GS' => 'Illes Geòrgia del Sud i Sandwich del Sud', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guaiana', + 'HK' => 'Hong Kong', + 'HM' => 'Illa Heard i Illes McDonald', + 'HN' => 'Hondures', + 'HR' => 'Croàcia', + 'HT' => 'Haití', + 'HU' => 'Hongria', + 'ID' => 'Indonèsia', + 'IE' => 'Irlanda', + 'IL' => 'Israel', + 'IM' => 'Illa de Man', + 'IN' => 'Índia', + 'IO' => 'Territori Britànic de l’Oceà Índic', + 'IQ' => 'Iraq', + 'IR' => 'República Islàmica d\'Iran', + 'IS' => 'Islàndia', + 'IT' => 'Itàlia', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordània', + 'JP' => 'Japó', + 'KE' => 'Kènia', + 'KG' => 'Kirguizistan', + 'KH' => 'Cambodja', + 'KI' => 'Kiribati', + 'KM' => 'Comores', + 'KN' => 'Saint Kitts i Nevis', + 'KP' => "Corea, República Popular Democràtica de", + 'KR' => 'Corea, República de', + 'KW' => 'Kuwait', + 'KY' => 'Illes Caiman', + 'KZ' => 'Kazakhstan', + 'LA' => "República Democràtica Popular Laos", + 'LB' => 'Líban', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Libèria', + 'LS' => 'Lesoto', + 'LT' => 'Lituània', + 'LU' => 'Luxemburg', + 'LV' => 'Letònia', + 'LY' => 'Líbia', + 'MA' => 'Marroc', + 'MC' => 'Mònaco', + 'MD' => 'Moldàvia', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (part francesa)', + 'MG' => 'Madagascar', + 'MH' => 'Illes Marshall', + 'MK' => 'Macedònia', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongòlia', + 'MO' => 'Macau', + 'MP' => 'Illes Mariannes del Nord', + 'MQ' => 'Martinica', + 'MR' => 'Mauritània', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Maurici', + 'MV' => 'Maldives', + 'MW' => 'Malaui', + 'MX' => 'Mèxic', + 'MY' => 'Malàisia', + 'MZ' => 'Moçambic', + 'N/A' => 'No aplicable (IP local...)', + 'NA' => 'Namíbia', + 'NC' => 'Nova Caledònia', + 'NE' => 'Níger', + 'NF' => 'Illa Norfolk', + 'NG' => 'Nigèria', + 'NI' => 'Nicaragua', + 'NL' => 'Països Baixos', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Naüru', + 'NU' => 'Niue', + 'NZ' => 'Nova Zelanda', + 'OM' => 'Oman', + 'PA' => 'Panamà', + 'PE' => 'Perú', + 'PF' => 'Polinèsia Francesa', + 'PG' => 'Papua Nova Guinea', + 'PH' => 'Filipines', + 'PK' => 'Pakistan', + 'PL' => 'Polònia', + 'PM' => 'Saint Pierre i Miquelon', + 'PN' => 'Illes Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguai', + 'QA' => 'Qatar', + 'RE' => 'Illa de la Reunió', + 'RO' => 'Romania', + 'RS' => 'Sèrbia', + 'RU' => 'Rússia', + 'RW' => 'Ruanda', + 'SA' => 'Aràbia Saudita', + 'SB' => 'Illes Salomó', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Suècia', + 'SG' => 'Singapur', + 'SH' => 'Santa Helena, Ascensió i Tristan da Cunha', + 'SI' => 'Eslovènia', + 'SJ' => 'Svalbard i Jan Mayen', + 'SK' => 'Eslovàquia', + 'SL' => 'Sierra Leona', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somàlia', + 'SR' => 'Surinam', + 'SS' => 'Sudan del Sud', + 'ST' => 'São Tomé i Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (part neerlandesa)', + 'SY' => 'Síria', + 'SZ' => 'Swazilàndia', + 'TC' => 'Illes Turks i Caicos', + 'TD' => 'Txad', + 'TF' => 'Territoris Francesos del Sud', + 'TG' => 'Togo', + 'TH' => 'Tailàndia', + 'TJ' => 'Tatgiquistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor Oriental', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunísia', + 'TO' => 'Tonga', + 'TR' => 'Turquia', + 'TT' => 'Trinidad i Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzània', + 'UA' => 'Ucraïna', + 'UG' => 'Uganda', + 'UM' => 'Illes Perifèriques Menors dels Eua', + 'US' => 'Estats Units d\'Amèrica', + 'UY' => 'Uruguai', + 'UZ' => 'Uzbekistan', + 'VA' => 'Ciutat del Vaticà', + 'VC' => 'Saint Vincent i les Grenadines', + 'VE' => 'Veneçuela', + 'VG' => 'Illes Verges britàniques', + 'VI' => 'Illes Verges Nord-americanes', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis i Futuna', + 'WS' => 'Samoa', + 'YE' => 'Iemen', + 'YT' => 'Mayotte', + 'ZA' => 'Sud-àfrica', + 'ZM' => 'Zàmbia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/ca/Dashboard.php b/modules/Admin/Language/ca/Dashboard.php new file mode 100644 index 00000000..3e484fdf --- /dev/null +++ b/modules/Admin/Language/ca/Dashboard.php @@ -0,0 +1,28 @@ + 'Panell de control', + 'welcome_message' => 'Benvinguts al panell de control.', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No hi ha podcasts publicats', + 'last_published' => 'Darrera publicació el {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodis', + 'not_found' => 'No hi ha episodis publicats', + 'last_published' => 'Darrera publicació el {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Emmagatzematge', + 'subtitle' => '{totalUploaded} de {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ca/Episode.php b/modules/Admin/Language/ca/Episode.php new file mode 100644 index 00000000..ba0ff1f2 --- /dev/null +++ b/modules/Admin/Language/ca/Episode.php @@ -0,0 +1,225 @@ + 'Temporada {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episodi {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Temporada {seasonNumber} episodi {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comentari} + other {# comentaris} + }', + 'all_podcast_episodes' => 'Tots els episodis del podcast', + 'back_to_podcast' => 'Tornar al podcast', + 'edit' => 'Editar', + 'preview' => 'Preview', + 'publish' => 'Publicar', + 'publish_edit' => 'Editar la publicació', + 'publish_date_edit' => 'Edita la data de publicació', + 'unpublish' => 'Desfer la publicació', + 'publish_error' => 'L\'episodi ja està publicat.', + 'publish_edit_error' => 'L\'episodi ja està publicat.', + 'publish_cancel_error' => 'L\'episodi ja està publicat.', + 'publish_date_edit_error' => 'L\'episodi encara no s\'ha publicat, no podeu editar-ne la data de publicació.', + 'publish_date_edit_future_error' => 'La data de publicació de l\'episodi només es pot establir en una data passada! Si voleu reprogramar-lo, cancel·leu-lo primer.', + 'publish_date_edit_success' => 'La data de publicació de l\'episodi ha estat actualitzada correctament!', + 'unpublish_error' => 'L\'episodi no està publicat.', + 'delete' => 'Eliminar', + 'go_to_page' => 'Anar a la pàgina ', + 'create' => 'Afegir un episodi', + 'publication_status' => [ + 'published' => 'Publicat', + 'with_podcast' => 'Publicat', + 'scheduled' => 'Programat', + 'not_published' => 'No publicat', + ], + 'with_podcast_hint' => 'Per ser publicat al mateix temps que el podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Cerca d\'un episodi', + 'clear' => 'Netejar la cerca', + 'submit' => 'Cercar', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episodi} + other {# episodis} + }', + 'episode' => 'Episodi', + 'visibility' => 'Visibilitat', + 'downloads' => 'Downloads', + 'comments' => 'Comentaris', + 'actions' => 'Accions', + ], + 'messages' => [ + 'createSuccess' => 'S\'ha creat l\'episodi correctament.', + 'editSuccess' => 'L\'episodi s\'ha actualitzat.', + 'publishSuccess' => '{publication_status, select, + published {L\'episodi s\'ha creat correctament.} + scheduled {S\'ha programat la publicació de l\'episodi.} + with_podcast {Aquest episodi serà publicat al mateix temps que el podcast.} + other {Aquest episodi no està publicat.} + }', + 'publishCancelSuccess' => 'S\'ha cancel·lat la publicació de l\'episodi.', + 'unpublishBeforeDeleteTip' => 'Heu de desfer la publicació de l\'episodi abans d\'esborrar-lo.', + 'scheduleDateError' => 'S\'ha de definir una data de publicació!', + 'deletePublishedEpisodeError' => 'Heu de desfer la publicació de l\'episodi abans d\'esborrar-lo.', + 'deleteSuccess' => 'S\'ha esborrat l\'episodi.', + 'deleteError' => 'No s\'ha pogut esborrar {type, select, + transcript {la transcripció} + chapters {els capítols} + image {la portada} + audio {l\'àudio} + other {el material} + } de l\'episodi.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Ja existeix un episodi amb aquest àlies.', + ], + 'form' => [ + 'file_size_error' => + 'El vostre fitxer és massa gran per ser pujat al servidor! La mida màxima és {0}. Augmenteu els valors de `memory_limit`, `upload_max_filesize` i `post_max_size` al vostre fitxer de configuració php i després reinicieu el vostre servidor web per carregar el vostre fitxer.', + 'audio_file' => 'Fitxer d’àudio', + 'audio_file_hint' => 'Trieu un fitxer d\'àudio .mp3 o .m4a', + 'info_section_title' => 'Informació de l\'episodi', + 'cover' => 'Portada de l\'episodi', + 'cover_hint' => + 'Si no configureu cap portada, s\'utilitzarà la portada del podcast.', + 'cover_size_hint' => 'La portada ha de ser quadrada i com a mínim de 1400 px d\'amplada i alçada.', + 'title' => 'Títol', + 'title_hint' => + 'Hauria de contenir un nom de l\'episodi clar i concís. No especifiqueu aquí els números d\'episodi o temporada.', + 'permalink' => 'Enllaç permanent', + 'season_number' => 'Temporada ', + 'episode_number' => 'Episodi', + 'type' => [ + 'label' => 'Tipus', + 'full' => 'Complet', + 'full_hint' => 'Contingut complet (l\'episodi)', + 'trailer' => 'Tràiler', + 'trailer_hint' => 'Contingut breu i promocional que presenta una vista prèvia d\'aquest programa', + 'bonus' => 'Bonificació', + 'bonus_hint' => 'Contingut addicional per al programa (per exemple, informació entre bastidors o entrevistes amb el repartiment) o contingut promocional creuat per a un altre programa', + ], + 'premium_title' => 'Prèmium', + 'premium' => 'L\'episodi ha de ser accessible només per a subscriptors prèmium', + 'parental_advisory' => [ + 'label' => 'Avís parental', + 'hint' => 'L\'episodi conté contingut explícit?', + 'undefined' => 'indefinit', + 'clean' => 'Net', + 'explicit' => 'Explícit', + ], + 'show_notes_section_title' => 'Mostrar les notes', + 'show_notes_section_subtitle' => + 'Fins a 4000 caràcters, sigueu clar i concís. Les notes del programa ajuden els oients potencials a trobar l\'episodi.', + 'description' => 'Descripció', + 'description_footer' => 'Al peu de la descripció', + 'description_footer_hint' => + 'Aquest text s\'afegeix al final de la descripció de cada episodi, és un bon lloc per introduir els vostres enllaços socials, per exemple.', + 'additional_files_section_title' => 'Fitxers addicionals', + 'additional_files_section_subtitle' => + 'Aquests fitxers poden ser utilitzats per altres plataformes per oferir una millor experiència al vostre públic. Consulteu el {podcastNamespaceLink} per obtenir més informació.', + 'location_section_title' => 'Ubicació', + 'location_section_subtitle' => 'De quin lloc tracta aquest episodi?', + 'location_name' => 'Nom i adreça de la ubicació', + 'location_name_hint' => 'Pot ser una ubicació real o fictícia', + 'transcript' => 'Transcripció (subtítols)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Baixar la transcripció', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'URL remota per a la transcripció', + 'transcript_file_delete' => 'Eliminar el fitxer de la transcripció', + 'chapters' => 'Capítols', + 'chapters_hint' => 'El fitxer ha de tenir el format de capítols JSON.', + 'chapters_download' => 'Baixar els capítols', + 'chapters_file' => 'Fitxer dels capítols', + 'chapters_remote_url' => 'URL remota del fitxer de capítols', + 'chapters_file_delete' => 'Eliminar el fitxer de capítols', + 'advanced_section_title' => 'Paràmetres avançats', + 'advanced_section_subtitle' => + 'Si necessiteu etiquetes RSS que Castopod no manega, configureu-les aquí.', + 'custom_rss' => 'Etiquetes RSS personalitzades pel podcast', + 'custom_rss_hint' => 'Això s\'injectarà dins de l\'etiqueta ❬item❭.', + 'block' => 'L\'episodi s\'ha d\'amagar dels catàlegs públics', + 'block_hint' => + 'L\'estat de visibilitat de l\'episodi: activar aquesta opció evita que l\'episodi aparegui a Apple Podcasts, Google Podcasts i qualsevol aplicació de tercers que extreu programes d\'aquests directoris. (No garantit)', + 'submit_create' => 'Crear un episodi', + 'submit_edit' => 'Desar l\'episodi', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Tornar al panell de control dels episodis', + 'post' => 'La vostra publicació d\'anunci', + 'post_hint' => + "Escriviu un missatge per anunciar la publicació del vostre episodi. El missatge s'emetrà a tots els vostres seguidors al Fediverse i apareixerà a la pàgina d'inici del vostre podcast.", + 'message_placeholder' => 'Escriviu un missatge...', + 'publication_date' => 'Data de publicació', + 'publication_method' => [ + 'now' => 'Ara', + 'schedule' => 'Programar', + 'with_podcast' => 'Publicar juntament amb el podcast', + ], + 'scheduled_publication_date' => 'Data de publicació programada', + 'scheduled_publication_date_clear' => 'Netejar la data de publicació', + 'scheduled_publication_date_hint' => + 'Podeu programar el llançament de l\'episodi fixant una data de publicació futura. Aquest camp ha de tenir el format AAAA-MM-DD HH:mm', + 'submit' => 'Publicar', + 'submit_edit' => 'Editar la publicació', + 'cancel_publication' => 'Cancel·lar la publicació', + 'message_warning' => 'No heu escrit cap missatge per la publicació del vostre anunci!', + 'message_warning_hint' => 'Tenir un missatge augmenta la implicació social, donant lloc a una millor visibilitat del vostre episodi.', + 'message_warning_submit' => 'Publicar de totes maneres', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nova data de publicació', + 'new_publication_date_hint' => 'Has de posar una data passada.', + 'submit' => 'Edita la data de publicació', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Si desfeu la publicació de l'episodi, se suprimiran tots els comentaris i publicacions associades amb ell i s'eliminarà del fil RSS del podcast.", + 'understand' => 'Entenc, vull desfer la publicació de l\'episodi', + 'submit' => 'Desfer la publicació', + ], + 'delete_form' => [ + 'disclaimer' => + "Si suprimiu l'episodi, se suprimiran tots els fitxers multimèdia, comentaris, videoclips i fragments d'àudio associats amb ell.", + 'understand' => 'Entenc, vull suprimir aquest episodi', + 'submit' => 'Eliminar', + ], + 'embed' => [ + 'title' => 'Reproductor incrustable', + 'label' => + 'Trieu un color de tema, copieu el reproductor incrustable al porta-retalls i enganxeu-lo al vostre lloc web.', + 'clipboard_iframe' => 'Copiar el reproductor incrustable al porta-retalls', + 'clipboard_url' => 'Copiar l\'adreça al porta-retalls', + 'dark' => 'Fosc', + 'dark-transparent' => 'Fosc i transparent', + 'light' => 'Clar', + 'light-transparent' => 'Clar i transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ca/EpisodeNavigation.php b/modules/Admin/Language/ca/EpisodeNavigation.php new file mode 100644 index 00000000..037761d4 --- /dev/null +++ b/modules/Admin/Language/ca/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Veure la pàgina de l\'episodi', + 'dashboard' => 'Panell de control de l\'episodi', + 'episode-view' => 'Inici', + 'episode-edit' => 'Editar l\'episodi', + 'episode-persons-manage' => 'Administrar persones', + 'embed-add' => 'Reproductor incrustable', + 'clips' => 'Retalls', + 'video-clips-list' => 'Vídeoclips', + 'video-clips-create' => 'Nou videoclip', + 'soundbites-list' => 'Fragments d\'àudio', + 'soundbites-create' => 'Nou fragment', +]; diff --git a/modules/Admin/Language/ca/Fediverse.php b/modules/Admin/Language/ca/Fediverse.php new file mode 100644 index 00000000..c24839b1 --- /dev/null +++ b/modules/Admin/Language/ca/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'No s\'ha trobat el compte!', + 'blockActorSuccess' => '{actor} ha estat bloquejat.', + 'unblockActorSuccess' => '{actor} ha estat desbloquejat.', + 'blockDomainSuccess' => '{domain} ha estat bloquejat.', + 'unblockDomainSuccess' => '{domain} ha estat desbloquejat.', + ], + 'blocked_actors' => 'Comptes bloquejats', + 'blocked_domains' => 'Dominis bloquejats', + 'block_lists_form' => [ + 'handle' => 'Àlias del compte', + 'handle_hint' => 'Escriviu el @nomusuari@domini del compte.', + 'domain' => 'Nom del domini', + 'submit' => 'Bloquejat!', + ], + 'list' => [ + 'actor' => 'Compte', + 'domain' => 'Nom del domini', + 'unblock' => 'Desbloquejar', + ], +]; diff --git a/modules/Admin/Language/ca/Home.php b/modules/Admin/Language/ca/Home.php new file mode 100644 index 00000000..efac49c0 --- /dev/null +++ b/modules/Admin/Language/ca/Home.php @@ -0,0 +1,14 @@ + 'Tots els podcasts', + 'no_podcast' => 'No s\'han trobat podcasts', +]; diff --git a/modules/Admin/Language/ca/Install.php b/modules/Admin/Language/ca/Install.php new file mode 100644 index 00000000..a8ae121c --- /dev/null +++ b/modules/Admin/Language/ca/Install.php @@ -0,0 +1,61 @@ + 'Configuració manual', + 'manual_config_subtitle' => + 'Creeu un fitxer `.env` amb la vostra configuració i actualitzeu la pàgina per continuar amb la instal·lació.', + 'form' => [ + 'instance_config' => 'Configuració de la instància', + 'hostname' => 'Nom del servidor (hostname)', + 'media_base_url' => 'URL de base pel multimèdia', + 'media_base_url_hint' => + 'Si utilitzeu un CDN i/o un servei d\'anàlisi de tràfic extern, podeu configurar-los aquí.', + 'admin_gateway' => 'Configurar la porta d\'enllaç (gateway)', + 'admin_gateway_hint' => + 'La ruta per accedir a l\'àrea d\'administració (p. ex., https://exemple.com/cp-admin). Està configurat per defecte com a cp-admin, us recomanem que el canvieu per motius de seguretat.', + 'auth_gateway' => 'Autenticació a la porta d\'enllaç', + 'auth_gateway_hint' => + 'La ruta per accedir a les pàgines d\'autenticació (p. ex. https://exemple.com/cp-auth). Està configurada per defecte com a cp-auth, us recomanem que el canvieu per motius de seguretat.', + 'database_config' => 'Configuració de la Base de Dades', + 'database_config_hint' => + 'Castopod s\'ha de connectar a la vostra base de dades MySQL (o MariaDB). Si no teniu aquesta informació necessària, poseu-vos en contacte amb l\'administrador del vostre servidor.', + 'db_hostname' => 'Nom del servidor (host) de la base de dades', + 'db_name' => 'Nom de la base de dades', + 'db_username' => 'Usuari de la base de dades', + 'db_password' => 'Contrasenya de la base de dades', + 'db_prefix' => 'Prefix de la base de dades', + 'db_prefix_hint' => + "El prefix emprat als noms de les taules de Castopod, deixeu-lo com està si no sabeu què significa.", + 'cache_config' => 'Configuració de la memòria cau', + 'cache_config_hint' => + 'Trieu el vostre gestor de memòria cau preferit. Deixeu-lo com a valor predeterminat si no teniu ni idea del que significa.', + 'cache_handler' => 'Gestor de memòria cau', + 'cacheHandlerOptions' => [ + 'file' => 'Fitxer', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Següent', + 'submit' => 'Finalitzar la instal·lació', + 'create_superadmin' => 'Crear el vostre compte de super-usuari', + 'email' => 'Correu electrònic', + 'username' => 'Nom de l\'usuari', + 'password' => 'Contrasenya', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'El vostre compte de superadministrador s\'ha creat correctament. Inicieu sessió per començar a fer podcasts!', + 'databaseConnectError' => + 'Castopod no s\'ha pogut connectar a la vostra base de dades. Editeu la configuració de la vostra base de dades i torneu-ho a provar.', + 'writeError' => + "No s'ha pogut crear/escriure el fitxer `.env`. Heu de crear-lo manualment seguint la plantilla de fitxer `.env.example` del paquet Castopod.", + ], +]; diff --git a/modules/Admin/Language/ca/Navigation.php b/modules/Admin/Language/ca/Navigation.php new file mode 100644 index 00000000..5fc3659b --- /dev/null +++ b/modules/Admin/Language/ca/Navigation.php @@ -0,0 +1,44 @@ + 'Ocultar/mostrar barra lateral', + 'go_to_website' => 'Anar al lloc web', + 'go_to_admin' => 'Anar al panell de control', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Panell de control', + 'admin' => 'Inici', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Tots els podcasts', + 'podcast-create' => 'Nou podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persones', + 'person-list' => 'Totes les persones', + 'person-create' => 'Persona nova', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Comptes bloquejats', + 'fediverse-blocked-domains' => 'Dominis bloquejats', + 'users' => 'Usuaris', + 'user-list' => 'Tots els usuaris', + 'user-create' => 'Nou usuari', + 'pages' => 'Pàgines', + 'page-list' => 'Totes les pàgines', + 'page-create' => 'Pàgina nova', + 'settings' => 'Preferències', + 'settings-general' => 'General', + 'settings-theme' => 'Tema', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'El meu compte', + 'change-password' => 'Canviar la contrasenya', + 'logout' => 'Tancar la sessió', + ], +]; diff --git a/modules/Admin/Language/ca/Notifications.php b/modules/Admin/Language/ca/Notifications.php new file mode 100644 index 00000000..35032ab1 --- /dev/null +++ b/modules/Admin/Language/ca/Notifications.php @@ -0,0 +1,19 @@ + 'Notificacions', + 'reply' => '{actor_username} ha respost a la vostra publicació', + 'favourite' => '{actor_username} ha marcat com a preferit la vostra publicació', + 'reblog' => '{actor_username} ha compartit la vostra publicació', + 'follow' => '{actor_username} t\'ha començat a seguir', + 'no_notifications' => 'Cap notificació', + 'mark_all_as_read' => 'Marca tot com a llegit', +]; diff --git a/modules/Admin/Language/ca/Page.php b/modules/Admin/Language/ca/Page.php new file mode 100644 index 00000000..26a9b5d3 --- /dev/null +++ b/modules/Admin/Language/ca/Page.php @@ -0,0 +1,30 @@ + 'Tornar a l\'inici', + 'page' => 'Pàgina', + 'all_pages' => 'Totes les pàgines', + 'create' => 'Nova pàgina', + 'go_to_page' => 'Anar a la pàgina ', + 'edit' => 'Editar pàgina', + 'delete' => 'Suprimir la pàgina', + 'form' => [ + 'title' => 'Títol', + 'permalink' => 'Enllaç permanent', + 'content' => 'Contingut', + 'submit_create' => 'Crear una pàgina', + 'submit_edit' => 'Desar', + ], + 'messages' => [ + 'createSuccess' => 'La pàgina "{pageTitle}" s\'ha creat correctament.', + 'editSuccess' => 'La pàgina s\'ha actualitzat correctament.', + ], +]; diff --git a/modules/Admin/Language/ca/Pager.php b/modules/Admin/Language/ca/Pager.php new file mode 100644 index 00000000..4401c891 --- /dev/null +++ b/modules/Admin/Language/ca/Pager.php @@ -0,0 +1,21 @@ + 'Navegació de pàgina', + 'first' => 'Primera', + 'previous' => 'Anterior', + 'next' => 'Següent', + 'last' => 'Darrera', + 'older' => 'Més antiga', + 'newer' => 'Més recent', + 'invalidTemplate' => '{0} no és una plantilla de pàgina vàlida.', + 'invalidPaginationGroup' => '{0} no és un grup de de paginació vàlida', +]; diff --git a/modules/Admin/Language/ca/Person.php b/modules/Admin/Language/ca/Person.php new file mode 100644 index 00000000..c82b805b --- /dev/null +++ b/modules/Admin/Language/ca/Person.php @@ -0,0 +1,65 @@ + 'Persones', + 'all_persons' => 'Totes les persones', + 'no_person' => 'No s\'ha trobat ningú.', + 'create' => 'Crear una persona', + 'view' => 'Veure la persona', + 'edit' => 'Editar la persona', + 'delete' => 'Esborrar la persona', + 'messages' => [ + 'createSuccess' => 'S\'ha creat la persona.', + 'editSuccess' => 'S\'ha actualitzat la persona.', + 'deleteSuccess' => 'S\'ha esborrat la persona.', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'L\'avatar ha de ser quadrat i com a mínim de 400 px d\'amplada i alçada.', + 'full_name' => 'Nom complet', + 'full_name_hint' => 'Aquest és el nom complet o àlies de la persona.', + 'unique_name' => 'Nom únic', + 'unique_name_hint' => 'Emprat en adreces URLs', + 'information_url' => 'URL informativa', + 'information_url_hint' => + 'URL d\'un recurs d\'informació rellevant sobre la persona, com ara una pàgina d\'inici o un perfil a una plataforma de tercers.', + 'submit_create' => 'Crear una persona', + 'submit_edit' => 'Desar canvis de la persona', + ], + 'podcast_form' => [ + 'title' => 'Administrar persones', + 'add_section_title' => 'Afegir una persona a aquest podcast', + 'add_section_subtitle' => 'Podeu triar diverses persones i rols.', + 'persons' => 'Persones', + 'persons_hint' => + 'Podeu seleccionar una o diverses persones amb les mateixes funcions. Primer heu de crear les persones.', + 'roles' => 'Rols', + 'roles_hint' => + 'Podeu seleccionar cap, un o diversos rols per a una persona.', + 'submit_add' => 'Afegir persones', + 'remove' => 'Eliminar', + ], + 'episode_form' => [ + 'title' => 'Administrar persones', + 'add_section_title' => 'Afegir persones a aquest episodi', + 'add_section_subtitle' => 'Podeu triar diverses persones i rols.', + 'persons' => 'Persones', + 'persons_hint' => + 'Podeu seleccionar una o diverses persones amb les mateixes funcions. Primer heu de crear les persones.', + 'roles' => 'Rols', + 'roles_hint' => + 'Podeu seleccionar cap, un o diversos rols per a una persona.', + 'submit_add' => 'Afegir persones', + 'remove' => 'Eliminar', + ], + 'credits' => 'Crèdits', +]; diff --git a/modules/Admin/Language/ca/Platforms.php b/modules/Admin/Language/ca/Platforms.php new file mode 100644 index 00000000..cfa50efb --- /dev/null +++ b/modules/Admin/Language/ca/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Visitar el lloc web de {platformName}', + 'register' => 'Register', + 'submit_url' => 'Enviar el vostre podcast a {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Mostrar a la pàgina d\'inici del podcast?', + 'on_embed' => 'Mostrar al reproductor incrustable?', + 'remove' => 'Suprimir {platformName}', + 'submit' => 'Desar', + 'messages' => [ + 'updateSuccess' => 'Els enllaços de les plataformes s\'han actualitzat correctament.', + 'removeLinkSuccess' => 'S\'ha eliminat l\'enllaç de la plataforma.', + 'removeLinkError' => + 'No s\'ha pogut eliminar l\'enllaç de la plataforma. Torneu a provar-ho.', + ], + 'description' => [ + 'podcasting' => 'L\'identificador del podcast en aquesta plataforma', + 'social' => 'L\'identificador del compte del podcast en aquesta plataforma', + 'funding' => 'Missatge de crida a l\'acció', + ], +]; diff --git a/modules/Admin/Language/ca/Podcast.php b/modules/Admin/Language/ca/Podcast.php new file mode 100644 index 00000000..022e8797 --- /dev/null +++ b/modules/Admin/Language/ca/Podcast.php @@ -0,0 +1,330 @@ + 'Tots els podcasts', + 'no_podcast' => 'No s\'han trobat podcasts!', + 'create' => 'Crear un podcast', + 'import' => 'Importar el podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Nou episodi', + 'view' => 'Veure el podcast', + 'edit' => 'Editar el podcast', + 'publish' => 'Publicar el podcast', + 'publish_edit' => 'Editar la publicació', + 'delete' => 'Suprimir el podcast', + 'see_episodes' => 'Veure els episodis', + 'see_contributors' => 'Veure els col·laboradors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Anar a la pàgina ', + 'latest_episodes' => 'Darrers episodis', + 'see_all_episodes' => 'Veure tots els episodis', + 'draft' => 'Esborrany', + 'messages' => [ + 'createSuccess' => 'Podcast creat correctament.', + 'editSuccess' => 'El podcast s´ha actualitzat correctament.', + 'importSuccess' => 'El podcast s\'ha importat correctament.', + 'deleteSuccess' => 'El podcast @{podcast_handle} s\'ha eliminat correctament.', + 'deletePodcastMediaError' => 'No s\'ha pogut eliminar {type, select, + cover {la portada} + banner {el bàner} + other {el material} + } del podcast.', + 'deleteEpisodeMediaError' => 'No s\'ha pogut eliminar {type, select, + transcript {la transcripció} + chapters {els capítols} + image {la portada} + audio {l\'àudio} + other {el material} + } de l\'episodi {episode_slug}.', + 'deletePodcastMediaFolderError' => 'No s\'ha pogut suprimir la carpeta multimèdia del podcast {folder_path}. Podeu eliminar-la manualment del vostre disc.', + 'podcastFeedUpdateSuccess' => 'Correctar actualització: {number_of_new_episodes, plural, + one {s\'ha afegit 1 episodi} + other {s\'han afegit # episodis} + } al podcast.', + 'podcastFeedUpToDate' => 'El podcast ja està actualitzat.', + 'publishError' => 'Aquest podcast ja està publicat o bé està programat per a la seva publicació.', + 'publishEditError' => 'Aquest podcast no està programat per a la seva publicació.', + 'publishCancelSuccess' => 'La publicació del podcast s\'ha cancel·lat correctament.', + 'scheduleDateError' => 'S\'ha de definir una data de publicació!', + ], + 'form' => [ + 'identity_section_title' => 'Identitat del podcast', + 'identity_section_subtitle' => 'Aquests camps permeten fer-se notar.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Portada del podcast', + 'cover_size_hint' => 'La portada ha de ser quadrada i com a mínim de 1400 px d\'amplada i alçada.', + 'banner' => 'Bàner del podcast', + 'banner_size_hint' => 'El bàner ha de tenir una proporció de 3:1 i tenir una amplada mínima de 1500 píxels.', + 'banner_delete' => 'Eliminar el bàner del podcast', + 'title' => 'Títol', + 'handle' => 'Àlias', + 'handle_hint' => + 'S\'utilitza per identificar el podcast. S\'accepten NOMÉS majúscules, minúscules, números i guions baixos.', + 'type' => [ + 'label' => 'Tipus', + 'episodic' => 'Episòdic', + 'episodic_hint' => 'Si els episodis estan pensats per ser consumits sense cap ordre específic. Els episodis més recents es presentaran primer.', + 'serial' => 'En sèrie', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Descripció', + 'classification_section_title' => 'Classificació', + 'classification_section_subtitle' => + 'Aquests camps afectaran el vostre públic i competència.', + 'language' => 'Idioma', + 'category' => 'Categoria', + 'category_placeholder' => 'Seleccioneu una categoria', + 'other_categories' => 'Altres categories', + 'parental_advisory' => [ + 'label' => 'Avís parental', + 'hint' => 'L\'episodi conté contingut explícit?', + 'undefined' => 'indefinit', + 'clean' => 'Net', + 'explicit' => 'Explícit', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Qui administra el podcast?', + 'owner_name' => 'Nom del propietari', + 'owner_name_hint' => + 'Només per a ús administratiu. Visible al fil RSS públic.', + 'owner_email' => 'Correu electrònic del propietari', + 'owner_email_hint' => + 'La majoria de plataformes l\'utilitzaran per verificar la propietat del podcast. Visible al fil RSS públic.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Editor', + 'publisher_hint' => + 'El grup encarregat de crear el programa. Sovint es refereix a l\'empresa matriu o a la xarxa d\'un podcast. Aquest camp de vegades s\'etiqueta com a "Autor".', + 'copyright' => 'Copyright', + 'location_section_title' => 'Ubicació', + 'location_section_subtitle' => 'De quin lloc tracta aquest podcast?', + 'location_name' => 'Nom i adreça de la ubicació', + 'location_name_hint' => 'Aquest pot ser un lloc real o fictici', + 'monetization_section_title' => 'Monetització', + 'monetization_section_subtitle' => + 'Guanyeu diners gràcies al vostre públic.', + 'premium' => 'Prèmium', + 'premium_by_default' => 'Els episodis s\'han d\'establir com a prèmium de manera predeterminada', + 'premium_by_default_hint' => 'Els episodis de pòdcast es marcaran com a prèmium de manera predeterminada. Encara podreu escollir configurar alguns episodis, tràilers o bonificacions com a públics.', + 'op3' => 'Projecte obert de prefix de pòdcast (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Valoreu les vostres dades estadístiques amb OP3, un servei d\'anàlisi de tercers de codi obert i de confiança. Compartiu, valideu i compareu les vostres dades d\'anàlisi amb l\'ecosistema de podcasting obert.', + 'op3_enable' => 'Habilita el servei d\'estadístiques OP3', + 'op3_enable_hint' => 'Per motius de seguretat, les dades d\'anàlisi dels episodis prèmium no es compartiran amb OP3.', + 'payment_pointer' => '`Payment Pointer` per a `Web Monetization`', + 'payment_pointer_hint' => + 'Aquí és on rebreu diners gràcies al servei `Web Monetization`', + 'advanced_section_title' => 'Paràmetres avançats', + 'advanced_section_subtitle' => + 'Si necessiteu etiquetes RSS que Castopod no manega, configureu-les aquí.', + 'custom_rss' => 'Etiquetes RSS personalitzades per al podcast', + 'custom_rss_hint' => 'Això s\'injectarà dins de l\'etiqueta ❬channel❭.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Nova adreça URL del fil RSS', + 'new_feed_url_hint' => 'Utilitzeu aquest camp quan us moveu a un altre domini o plataforma d\'allotjament de podcasts. De manera predeterminada, el valor s\'estableix a l\'URL RSS actual si s\'importa el podcast.', + 'old_feed_url' => 'Antiga adreça URL del fil RSS', + 'partnership' => 'Socis', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL de l\'enllaç', + 'partner_image_url' => 'URL de la imatge', + 'partner_id_hint' => 'El vostre propi ID de soci', + 'partner_link_url_hint' => 'L\'adreça genèrica de l\'enllaç del soci', + 'partner_image_url_hint' => 'L\'adreça genèrica de la imatge del soci', + 'block' => 'El podcast s\'ha d\'amagar als catàlegs públics', + 'block_hint' => + 'L\'estat de visibilitat del podcast: activar aquesta opció evita que el podcast aparegui a Apple Podcasts, Google Podcasts i qualsevol aplicació de tercers que extreu programes d\'aquests directoris. (No garantit)', + 'complete' => 'El podcast no tindrà capítols nous', + 'lock' => 'Eviteu que es el podcast sigui copiat', + 'lock_hint' => + 'L\'objectiu és indicar a altres plataformes de podcasts si tenen permís per importar aquest podcast i els seus episodis. Un valor de sí significa que s\'ha de rebutjar qualsevol intent d\'importar aquest podcast a una altra plataforma.', + 'submit_create' => 'Crear un podcast', + 'submit_edit' => 'Desar el podcast', + ], + 'category_options' => [ + 'uncategorized' => 'sense categoria', + 'arts' => 'Arts', + 'business' => 'Negocis', + 'comedy' => 'Comèdia', + 'education' => 'Educació', + 'fiction' => 'Ficció', + 'government' => 'Govern', + 'health_and_fitness' => 'Salut i fitness', + 'history' => 'Història', + 'kids_and_family' => 'Quitxalla i Família', + 'leisure' => 'Lleure', + 'music' => 'Música', + 'news' => 'Notícies', + 'religion_and_spirituality' => 'Religió i espiritualitat', + 'science' => 'Ciència', + 'society_and_culture' => 'Societat i cultura', + 'sports' => 'Esports', + 'technology' => 'Tecnologia', + 'true_crime' => 'Crims reals', + 'tv_and_film' => 'TV i películ·les', + 'books' => 'Llibres', + 'design' => 'Disseny', + 'fashion_and_beauty' => 'Moda i bellesa', + 'food' => 'Menjar', + 'performing_arts' => 'Arts escèniques', + 'visual_arts' => 'Arts visuals', + 'careers' => 'Carreres', + 'entrepreneurship' => 'Empreniment', + 'investing' => 'Inversió', + 'management' => 'Gestió', + 'marketing' => 'Màrqueting', + 'non_profit' => 'Sense ànim de lucre', + 'comedy_interviews' => 'Entrevistes de comèdia', + 'improv' => 'Millora', + 'stand_up' => 'Monòlegs', + 'courses' => 'Cursos', + 'how_to' => 'Tutorials', + 'language_learning' => 'Aprenentatge d\'idiomes', + 'self_improvement' => 'Millora personal', + 'comedy_fiction' => 'Comèdia de ficció', + 'drama' => 'Drama', + 'science_fiction' => 'Ciència-ficció', + 'alternative_health' => 'Salut alternativa', + 'fitness' => 'Fitness', + 'medicine' => 'Medicina', + 'mental_health' => 'Salut mental', + 'nutrition' => 'Nutrició', + 'sexuality' => 'Sexualitat', + 'education_for_kids' => 'Educació infantil', + 'parenting' => 'Criança', + 'pets_and_animals' => 'Mascotes i animals', + 'stories_for_kids' => 'Contes per la quitxalla', + 'animation_and_manga' => 'Animació i manga', + 'automotive' => 'Automoció', + 'aviation' => 'Aviació', + 'crafts' => 'Artesanies', + 'games' => 'Jocs', + 'hobbies' => 'Aficions', + 'home_and_garden' => 'Llar i jardineria', + 'video_games' => 'Videojocs', + 'music_commentary' => 'Música, anàlisi', + 'music_history' => 'Música, història', + 'music_interviews' => 'Música, entrevistes', + 'business_news' => 'Notícies sobre negocis', + 'daily_news' => 'Notícies del dia', + 'entertainment_news' => 'Notícies d\'entreteniment', + 'news_commentary' => 'Comentaris sobre notícies', + 'politics' => 'Política', + 'sports_news' => 'Notícies d\'esports', + 'tech_news' => 'Notícies de tecnologia', + 'buddhism' => 'Budisme', + 'christianity' => 'Cristianisme', + 'hinduism' => 'Hinduisme', + 'islam' => 'Islam', + 'judaism' => 'Judaisme', + 'religion' => 'Religió', + 'spirituality' => 'Espiritualitat', + 'astronomy' => 'Astronomia', + 'chemistry' => 'Química', + 'earth_sciences' => 'Ciències ambientals', + 'life_sciences' => 'Ciències de la Vida', + 'mathematics' => 'Matemàtiques', + 'natural_sciences' => 'Ciències naturals', + 'nature' => 'Natura', + 'physics' => 'Física', + 'social_sciences' => 'Ciències socials', + 'documentary' => 'Documentals', + 'personal_journals' => 'Diaris personals', + 'philosophy' => 'Filosofia', + 'places_and_travel' => 'Llocs i viatges', + 'relationships' => 'Relacions', + 'baseball' => 'Beisbol', + 'basketball' => 'Bàsquet', + 'cricket' => 'Criquet', + 'fantasy_sports' => 'Esports de fantasia', + 'football' => 'Futbol', + 'golf' => 'Golf', + 'hockey' => 'Hoquei', + 'rugby' => 'Rugby', + 'running' => 'Córrer', + 'soccer' => 'Futbol soccer', + 'swimming' => 'Natació', + 'tennis' => 'Tennis', + 'volleyball' => 'Voleibol', + 'wilderness' => 'Naturalesa', + 'wrestling' => 'Lluita lliure', + 'after_shows' => 'Espectacles nocturns', + 'film_history' => 'Història del cinema', + 'film_interviews' => 'Entrevistes i cinema', + 'film_reviews' => 'Ressenyes de cinema', + 'tv_reviews' => 'Ressenyes de TV', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Tornar al panell de control del podcast', + 'post' => 'La vostra publicació d\'anunci', + 'post_hint' => + "Escriviu un missatge per anunciar la publicació del teu podcast. El missatge apareixerà destacat a la pàgina d'inici del vostre podcast.", + 'message_placeholder' => 'Escriviu un missatge...', + 'submit' => 'Publicar', + 'publication_date' => 'Data de publicació', + 'publication_method' => [ + 'now' => 'Ara', + 'schedule' => 'Programar', + ], + 'scheduled_publication_date' => 'Data de publicació programada', + 'scheduled_publication_date_hint' => + 'Podeu programar el llançament del podcast fixant una data de publicació futura. Aquest camp ha de tenir el format AAAA-MM-DD HH:mm', + 'submit_edit' => 'Editar la publicació', + 'cancel_publication' => 'Cancel·lar la publicació', + 'message_warning' => 'No heu escrit cap missatge per la publicació del vostre anunci!', + 'message_warning_hint' => 'Tenir un missatge augmenta la implicació social, donant lloc a una millor visibilitat del vostre podcast.', + 'message_warning_submit' => 'Publicar de totes maneres', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'mode d\'esborrany', + 'not_published' => 'Aquest podcast encara no s\'ha publicat.', + 'scheduled' => 'La publicació d\'aquest podcast està programada el dia {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Si suprimiu el podcast, se suprimiran tots els episodis, fitxers multimèdia, publicacions i estadístiques associats amb ell. Aquesta acció és irreversible, no els podreu recuperar després.", + 'understand' => 'Entenc, vull que el podcast s\'elimini permanentment', + 'submit' => 'Eliminar', + ], + 'by' => 'Per {publisher}', + 'season' => 'Temporada {seasonNumber}', + 'list_of_episodes_year' => 'Episodis del {year} ({episodeCount})', + 'list_of_episodes_season' => + 'Episodis de la temporada {seasonNumber} ({episodeCount})', + 'no_episode' => 'No s\'han trobat episodis.', + 'follow' => 'Seguir', + 'followers' => '{numberOfFollowers, plural, + one {# seguidor} + other {# seguidors} + }', + 'posts' => '{numberOfPosts, plural, + one {# publicació} + other {# publicacions} + }', + 'activity' => 'Activitat', + 'episodes' => 'Episodis', + 'sponsor' => 'Patrocinador', + 'funding_links' => 'Enllaços de finançament per {podcastTitle}', + 'find_on' => 'Trobar {podcastTitle} a', + 'listen_on' => 'Escoltant', +]; diff --git a/modules/Admin/Language/ca/PodcastNavigation.php b/modules/Admin/Language/ca/PodcastNavigation.php new file mode 100644 index 00000000..bcbc8120 --- /dev/null +++ b/modules/Admin/Language/ca/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Anar a la pàgina del podcast', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Panell de control del podcast', + 'podcast-view' => 'Inici', + 'podcast-edit' => 'Editar el podcast', + 'podcast-persons-manage' => 'Administrar persones', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodis', + 'episode-list' => 'Tots els episodis', + 'episode-create' => 'Nou episodi', + 'analytics' => 'Estadístiques', + 'podcast-analytics' => 'Visió general de l\'audiència', + 'podcast-analytics-webpages' => 'Visites a pàgines web', + 'podcast-analytics-locations' => 'Ubicacions', + 'podcast-analytics-unique-listeners' => 'Oients únics', + 'podcast-analytics-players' => 'Reproductors', + 'podcast-analytics-listening-time' => 'Temps d\'escolta', + 'podcast-analytics-time-periods' => 'Períodes de temps', + 'monetization' => 'Monetization', + 'subscription-list' => 'Totes les subscripcions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Col·laboradors', + 'contributor-list' => 'Tots els col·laboradors', + 'contributor-add' => 'Afegir un col·laborador', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Xarxes socials', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ca/Settings.php b/modules/Admin/Language/ca/Settings.php new file mode 100644 index 00000000..a0ba0476 --- /dev/null +++ b/modules/Admin/Language/ca/Settings.php @@ -0,0 +1,58 @@ + 'Configuració general', + 'instance' => [ + 'title' => 'Instància', + 'site_icon' => 'Icona del lloc', + 'site_icon_delete' => 'Esborra la icona del lloc', + 'site_icon_hint' => 'Les icones del lloc són el que veieu a les pestanyes del navegador, a la barra d\'adreces d\'interès i quan afegiu un lloc web com a drecera als dispositius mòbils.', + 'site_icon_helper' => 'La icona ha de ser quadrada i com a mínim 512 píxels d\'ample i d\'alçada.', + 'site_name' => 'Nom del lloc', + 'site_description' => 'Descripció de la web', + 'submit' => 'Desar', + 'editSuccess' => 'La instància s\'ha actualitzat correctament.', + 'deleteIconSuccess' => 'La icona del lloc s\'ha eliminat correctament.', + ], + 'images' => [ + 'title' => 'Imatges', + 'subtitle' => 'Aquí podeu regenerar totes les imatges en funció dels originals que s\'han pujat. S\'utilitzarà si trobeu que falten algunes imatges. Aquesta tasca pot portar una estona.', + 'regenerate' => 'Regenerar les imatges', + 'regenerationSuccess' => 'Totes les imatges s\'han regenerat correctament.', + ], + 'housekeeping' => [ + 'title' => 'Tasques de neteja', + 'subtitle' => 'Realitzar diferents tasques de neteja. Utilitzeu aquesta funció si mai trobeu problemes amb els fitxers multimèdia o la integritat de les dades. Aquestes tasques poden trigar una estona.', + 'reset_counts' => 'Restablir els comptes', + 'reset_counts_helper' => 'Aquesta opció tornarà a calcular i restablir tots els recomptes de dades (nombre de seguidors, publicacions, comentaris, …).', + 'rewrite_media' => 'Reescriure les metadades multimèdia', + 'rewrite_media_helper' => 'Aquesta opció suprimirà tots els fitxers multimèdia superflus i els recrearà (imatges, fitxers d\'àudio, transcripcions, capítols, ...)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Esborrar tota la memòria cau', + 'clear_cache_helper' => 'Aquesta opció esborrarà la memòria cau redis o els fitxers de memòria cau.', + 'run' => 'Executar la neteja', + 'runSuccess' => 'S\'ha conclòs correctament la neteja!', + ], + 'theme' => [ + 'title' => 'Tema', + 'accent_section_title' => 'Color d\'èmfasi', + 'accent_section_subtitle' => 'Trieu el color per determinar l\'aspecte de totes les pàgines públiques.', + 'pine' => 'Pi', + 'crimson' => 'Carmesí', + 'amber' => 'Ambre', + 'lake' => 'Llac', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Desar', + 'setInstanceThemeSuccess' => 'El tema s\'ha actualitzat correctament.', + ], +]; diff --git a/modules/Admin/Language/ca/Soundbite.php b/modules/Admin/Language/ca/Soundbite.php new file mode 100644 index 00000000..0a1e5eae --- /dev/null +++ b/modules/Admin/Language/ca/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Fragments d\'àudio', + 'soundbite' => 'Fragment d\'àudio', + ], + 'messages' => [ + 'createSuccess' => 'El fragment d\'àudio s\'ha creat correctament.', + 'deleteSuccess' => 'El fragment d\'àudio s\'ha suprimit correctament.', + ], + 'form' => [ + 'title' => 'Nou fragment', + 'soundbite_title' => 'Títol del fragment', + 'start_time' => 'Començar a', + 'duration' => 'Durada', + 'submit' => 'Crear un fragment', + ], + 'play' => 'Reproduir el fragment', + 'stop' => 'Aturar el fragment', + 'create' => 'Nou fragment', + 'delete' => 'Suprimir el fragment', +]; diff --git a/modules/Admin/Language/ca/Validation.php b/modules/Admin/Language/ca/Validation.php new file mode 100644 index 00000000..fc83ea02 --- /dev/null +++ b/modules/Admin/Language/ca/Validation.php @@ -0,0 +1,17 @@ + + '{field} no és una imatge, o no és prou ample o alt.', + 'is_image_ratio' => + '{field} no és una imatge o no té la proporció correcta.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ca/VideoClip.php b/modules/Admin/Language/ca/VideoClip.php new file mode 100644 index 00000000..b8b49f80 --- /dev/null +++ b/modules/Admin/Language/ca/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Vídeoclips', + 'status' => [ + 'label' => 'Estat', + 'queued' => 'en cua', + 'queued_hint' => 'El clip està esperant a ser processat.', + 'pending' => 'pendent', + 'pending_hint' => 'El clip es generarà aviat.', + 'running' => 'en execució', + 'running_hint' => 'S\'està generant el clip.', + 'failed' => 'ha fallat', + 'failed_hint' => 'No s\'ha pogut generar el clip: error de l\'script.', + 'passed' => 'passat', + 'passed_hint' => 'El clip s\'ha generat correctament.', + ], + 'clip' => 'Clip', + 'duration' => 'Duració de la tasca', + ], + 'title' => 'Videoclip: {videoClipLabel}', + 'download_clip' => 'Baixar el clip', + 'create' => 'Nou videoclip', + 'go_to_page' => 'Anar a la pàgina del clip ', + 'retry' => 'Intentar de nou la generació del clip', + 'delete' => 'Eliminar el clip', + 'logs' => 'Registres de la tasca', + 'messages' => [ + 'alreadyExistingError' => 'El videoclip que intenteu crear ja existeix!', + 'addToQueueSuccess' => 'El videoclip s\'ha afegit a la cua, a l\'espera de ser creat!', + 'deleteSuccess' => 'El videoclip s\'ha eliminat correctament.', + ], + 'format' => [ + 'landscape' => 'Horitzontal', + 'portrait' => 'Vertical', + 'squared' => 'Quadrat', + ], + 'form' => [ + 'title' => 'Nou videoclip', + 'params_section_title' => 'Paràmetres del videoclip', + 'clip_title' => 'Títol del videoclip', + 'format' => [ + 'label' => 'Trieu el format', + 'landscape_hint' => 'Amb una proporció de 16:9, els vídeos horitzontals són ideals per a PeerTube, Youtube i Vimeo.', + 'portrait_hint' => 'Amb una proporció de 9:16, els vídeos verticals són ideals per a TikTok, curts de Youtube i històries d\'Instagram.', + 'squared_hint' => 'Amb una proporció 1:1, els vídeos quadrats són ideals per a Mastodon, Facebook, Twitter i LinkedIn.', + ], + 'theme' => 'Trieu un tema', + 'start_time' => 'Començar a', + 'duration' => 'Durada', + 'trim_start' => 'Retallar l\'inici', + 'trim_end' => 'Retallar el final', + 'submit' => 'Crear videoclip', + ], + 'requirements' => [ + 'title' => 'Falten requisits', + 'missing' => 'Et falten requisits. Assegureu-vos d\'afegir tots els elements necessaris per poder crear un vídeo per a aquest episodi.', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Llibreria `FreeType` per a GD', + 'transcript' => 'Fitxer de la transcripció (.srt)', + ], +]; diff --git a/modules/Admin/Language/da/AboutCastopod.php b/modules/Admin/Language/da/AboutCastopod.php new file mode 100644 index 00000000..7ac4aeca --- /dev/null +++ b/modules/Admin/Language/da/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Om Castopod', + 'host_name' => 'Værtsnavn', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operativsystem', + 'languages' => 'Sprog', + 'update_database' => 'Opdater databasen', + 'messages' => [ + 'databaseUpdateSuccess' => 'Databasen er opdateret!', + ], +]; diff --git a/modules/Admin/Language/da/Breadcrumb.php b/modules/Admin/Language/da/Breadcrumb.php new file mode 100644 index 00000000..f02c83ac --- /dev/null +++ b/modules/Admin/Language/da/Breadcrumb.php @@ -0,0 +1,57 @@ + 'brødkrumme', + config('Admin') + ->gateway => 'Hjem', + 'podcasts' => 'podcasts', + 'episodes' => 'episoder', + 'subscriptions' => 'abonnementer', + 'contributors' => 'bidragydere', + 'pages' => 'sider', + 'settings' => 'indstillinger', + 'theme' => 'tema', + 'about' => 'om', + 'add' => 'tilføj', + 'new' => 'ny', + 'edit' => 'redigér', + 'persons' => 'personer', + 'publish' => 'publicér', + 'publish-edit' => 'redigér udgivelse', + 'publish-date-edit' => 'redigér udgivelsesdato', + 'unpublish' => 'afpublicér', + 'delete' => 'slet', + 'remove' => 'fjern', + 'fediverse' => 'fediverset', + 'blocked-actors' => 'blokerede aktører', + 'blocked-domains' => 'blokerede domæner', + 'users' => 'brugere', + 'my-account' => 'min konto', + 'change-password' => 'skift adgangskode', + 'imports' => 'importer', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforme', + 'social' => 'sociale netværk', + 'funding' => 'finansiering', + 'monetization-other' => 'other monetization', + 'analytics' => 'analyse', + 'locations' => 'lokationer', + 'webpages' => 'websider', + 'unique-listeners' => 'unikke lyttere', + 'players' => 'afspillere', + 'listening-time' => 'lyttetid', + 'time-periods' => 'periode', + 'soundbites' => 'lydbid', + 'video-clips' => 'videoklip', + 'embed' => 'integreret afspiller', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/da/Charts.php b/modules/Admin/Language/da/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/da/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/da/Common.php b/modules/Admin/Language/da/Common.php new file mode 100644 index 00000000..b53eff26 --- /dev/null +++ b/modules/Admin/Language/da/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Indlæser…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/da/Countries.php b/modules/Admin/Language/da/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/da/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/da/Dashboard.php b/modules/Admin/Language/da/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/da/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/da/Episode.php b/modules/Admin/Language/da/Episode.php new file mode 100644 index 00000000..7fad23ff --- /dev/null +++ b/modules/Admin/Language/da/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episoden er allerede publiceret.', + 'publish_cancel_error' => 'Episoden er allerede publiceret.', + 'publish_date_edit_error' => 'Episode er endnu ikke blevet offentliggjort. Du kan ikke redigere dens publiceringsdato.', + 'publish_date_edit_future_error' => 'Episodes publiceringsdato kan kun indstilles til en tidligere dato! Hvis du ønsker at omlægge den, så afpublicér den først.', + 'publish_date_edit_success' => 'Episodens udgivelsesdato er blevet opdateret!', + 'unpublish_error' => 'Episoden er ikke publiceret.', + 'delete' => 'Slet', + 'go_to_page' => 'Gå til side', + 'create' => 'Tilføj en episode', + 'publication_status' => [ + 'published' => 'Udgivet', + 'with_podcast' => 'Udgivet', + 'scheduled' => 'Planlagt', + 'not_published' => 'Ikke offentliggjort', + ], + 'with_podcast_hint' => 'Skal offentliggøres samtidig med podcasten', + 'list' => [ + 'search' => [ + 'placeholder' => 'Søg efter en episode', + 'clear' => 'Ryd søgning', + 'submit' => 'Søg', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episoder} + }', + 'episode' => 'Episode', + 'visibility' => 'Synlighed', + 'downloads' => 'Downloads', + 'comments' => 'Kommentarer', + 'actions' => 'Handlinger', + ], + 'messages' => [ + 'createSuccess' => 'Episoden er blevet oprettet!', + 'editSuccess' => 'Episoden er blevet opdateret!', + 'publishSuccess' => '{publication_status, select, + published {Episode udgivet!} + scheduled {Episodeudgivelse planlagt!} + with_podcast {Denne episode vil blive offentliggjort samtidig med podcasten.} + other {Denne episode er ikke offentliggjort.} + }', + 'publishCancelSuccess' => 'Udgivelsen blev annulleret!', + 'unpublishBeforeDeleteTip' => 'Du skal afpublicere episoden, før du sletter den.', + 'scheduleDateError' => 'Udgivelsesdato skal være sat!', + 'deletePublishedEpisodeError' => 'Afpublicér venligst episoden, før du sletter den.', + 'deleteSuccess' => 'Episode slettet succesfuldt!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/da/EpisodeNavigation.php b/modules/Admin/Language/da/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/da/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/da/Fediverse.php b/modules/Admin/Language/da/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/da/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/da/Home.php b/modules/Admin/Language/da/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/da/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/da/Install.php b/modules/Admin/Language/da/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/da/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/da/Navigation.php b/modules/Admin/Language/da/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/da/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/da/Notifications.php b/modules/Admin/Language/da/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/da/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/da/Page.php b/modules/Admin/Language/da/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/da/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/da/Pager.php b/modules/Admin/Language/da/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/da/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/da/Person.php b/modules/Admin/Language/da/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/da/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/da/Platforms.php b/modules/Admin/Language/da/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/da/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/da/Podcast.php b/modules/Admin/Language/da/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/da/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/da/PodcastNavigation.php b/modules/Admin/Language/da/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/da/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/da/Settings.php b/modules/Admin/Language/da/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/da/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/da/Soundbite.php b/modules/Admin/Language/da/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/da/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/da/Validation.php b/modules/Admin/Language/da/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/da/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/da/VideoClip.php b/modules/Admin/Language/da/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/da/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/de/AboutCastopod.php b/modules/Admin/Language/de/AboutCastopod.php new file mode 100644 index 00000000..7e8780ad --- /dev/null +++ b/modules/Admin/Language/de/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Über Castopod', + 'host_name' => 'Hostname', + 'version' => 'Castopod Version', + 'php_version' => 'PHP Version', + 'os' => 'Betriebssystem', + 'languages' => 'Sprachen', + 'update_database' => 'Datenbank aktualisieren', + 'messages' => [ + 'databaseUpdateSuccess' => 'Die Datenbank ist aktuell!', + ], +]; diff --git a/modules/Admin/Language/de/Breadcrumb.php b/modules/Admin/Language/de/Breadcrumb.php new file mode 100644 index 00000000..986f03dd --- /dev/null +++ b/modules/Admin/Language/de/Breadcrumb.php @@ -0,0 +1,57 @@ + 'Pfad', + config('Admin') + ->gateway => 'Startseite', + 'podcasts' => 'Podcasts', + 'episodes' => 'Folgen', + 'subscriptions' => 'Abonnements', + 'contributors' => 'Mitwirkende', + 'pages' => 'Seiten', + 'settings' => 'Einstellungen', + 'theme' => 'Erscheinungsbild', + 'about' => 'Über', + 'add' => 'hinzufügen', + 'new' => 'neu', + 'edit' => 'bearbeiten', + 'persons' => 'Mitwirkende', + 'publish' => 'veröffentlichen', + 'publish-edit' => 'Veröffentlichung bearbeiten', + 'publish-date-edit' => 'Veröffentlichungsdatum bearbeiten', + 'unpublish' => 'zurückziehen', + 'delete' => 'löschen', + 'remove' => 'Entfernen', + 'fediverse' => 'Fediversum', + 'blocked-actors' => 'blockierte Konten', + 'blocked-domains' => 'Blockierte Domains', + 'users' => 'Benutzer', + 'my-account' => 'Mein Konto', + 'change-password' => 'Passwort ändern', + 'imports' => 'Importe', + 'sync-feeds' => 'Feeds synchronisieren', + 'platforms' => 'Plattformen', + 'social' => 'soziale Netzwerke', + 'funding' => 'Finanzierung', + 'monetization-other' => 'sonstige Monetarisierung', + 'analytics' => 'Statistiken', + 'locations' => 'Orte', + 'webpages' => 'Webseiten', + 'unique-listeners' => 'eindeutige Zuhörer', + 'players' => 'Podcast-Player', + 'listening-time' => 'Hörzeit', + 'time-periods' => 'Zeiträume', + 'soundbites' => 'Tonschnipsel', + 'video-clips' => 'Videoclips', + 'embed' => 'einbettbarer Spieler', + 'notifications' => 'Benachrichtigungen', + 'suspend' => 'Unterbrechen', +]; diff --git a/modules/Admin/Language/de/Charts.php b/modules/Admin/Language/de/Charts.php new file mode 100644 index 00000000..89cea21b --- /dev/null +++ b/modules/Admin/Language/de/Charts.php @@ -0,0 +1,41 @@ + 'Download von Folgen nach Diensten (für die vergangene Woche)', + 'by_player_weekly' => 'Downloads von Folgen nach Player (für die vergangene Woche)', + 'by_player_yearly' => 'Downloads von Folgen nach Player (für das vergangene Jahr)', + 'by_device_weekly' => 'Downloads von Folgen nach Gerät (für die vergangene Woche)', + 'by_os_weekly' => 'Downloads von Folgen nach Betriebssystem (für die vergangene Woche)', + 'podcast_by_region' => 'Downloads von Folgen nach Region (für die vergangene Woche)', + 'unique_daily_listeners' => 'Tägliche eindeutige Zuhörer', + 'unique_monthly_listeners' => 'Monatliche eindeutige Zuhörer', + 'by_browser' => 'Nutzung der Webseiten nach Browser (für die vergangene Woche)', + 'podcast_by_day' => 'Tägliche Downloads von Folgen', + 'podcast_by_month' => 'Monatliche Downloads von Folgen', + 'episode_by_day' => 'Tägliche Downloads von Folgen (die ersten 60 Tage)', + 'episode_by_month' => 'Monatliche Downloads', + 'episodes_by_day' => + 'Downloads der letzten 5 Folgen (während der ersten 60 Tage)', + 'by_country_weekly' => 'Downloads von Folgen nach Ländern (für die vergangene Woche)', + 'by_country_yearly' => 'Downloads von Folgen nach Ländern (für das vergangene Jahr)', + 'by_domain_weekly' => 'Besuche der Webseiten nach Quelle (für die vergangene Woche)', + 'by_domain_yearly' => 'Besuche der Webseiten nach Quelle (für das vergangene Jahr)', + 'by_entry_page' => 'Besuche der Hauptseite (für die vergangene Woche)', + 'podcast_bots' => 'Bots (Crawler)', + 'daily_listening_time' => 'Tägliche kumulative Hörzeit', + 'monthly_listening_time' => 'Monatliche kumulative Hörzeit', + 'by_weekday' => 'Nach Wochentag (für die letzten 60 Tage)', + 'by_hour' => 'Nach Tageszeit (für die letzten 60 Tage)', + 'podcast_by_bandwidth' => 'Täglich genutzte Bandbreite (in MB)', + 'total_storage_by_month' => 'Monatlicher Speicher (in MB)', + 'total_bandwidth_by_month' => 'Monatlich genutzte Bandbreite (in MB)', + 'total_bandwidth_by_month_limit' => 'Begrenzt auf {totalBandwidth} pro Monat', +]; diff --git a/modules/Admin/Language/de/Common.php b/modules/Admin/Language/de/Common.php new file mode 100644 index 00000000..cc668a33 --- /dev/null +++ b/modules/Admin/Language/de/Common.php @@ -0,0 +1,52 @@ + 'Ja', + 'no' => 'Nein', + 'cancel' => 'Abbrechen', + 'optional' => 'Optional', + 'more' => 'Mehr', + 'no_data' => 'Keine Daten gefunden!', + 'close' => 'Schließen', + 'edit' => 'Bearbeiten', + 'copy' => 'Kopieren', + 'copied' => 'Kopiert!', + 'home' => 'Startseite', + 'explicit' => 'Anstößig', + 'powered_by' => 'Betrieben mit {castopod}', + 'actions' => 'Aktionen', + 'pageInfo' => 'Seite {currentPage} von {pageCount}', + 'go_back' => 'Zurück', + 'forms' => [ + 'editor' => [ + 'write' => 'Schreiben', + 'preview' => 'Vorschau', + 'help' => 'Unterstützt durch Markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Klicke zur Auswahl', + 'loadingText' => 'Wird geladen…', + 'noResultsText' => 'Keine Ergebnisse gefunden', + 'noChoicesText' => 'Keine Auswahl zur Auswahl', + 'maxItemText' => 'Weitere Elemente können nicht hinzugefügt werden', + ], + 'upload_file' => 'Eine Datei hochladen', + 'remote_url' => 'Externe URL', + 'save' => 'Speichern', + ], + 'play_episode_button' => [ + 'play' => 'Abspielen', + 'playing' => 'Spielt', + ], + 'size_limit' => 'Größenlimit: {0}.', + 'choose_interact' => 'Wählen Sie, wie Sie interagieren möchten', + 'view' => 'Ansicht', +]; diff --git a/modules/Admin/Language/de/Countries.php b/modules/Admin/Language/de/Countries.php new file mode 100644 index 00000000..4e0564f1 --- /dev/null +++ b/modules/Admin/Language/de/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Vereinigte Arabische Emirate', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua und Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albanien', + 'AM' => 'Armenien', + 'AO' => 'Angola', + 'AQ' => 'Antarktis', + 'AR' => 'Argentinien', + 'AS' => 'Amerikanisch-Samoa', + 'AT' => 'Österreich', + 'AU' => 'Australien', + 'AW' => 'Aruba', + 'AX' => 'Åland-Inseln', + 'AZ' => 'Aserbaidschan', + 'BA' => 'Bosnien und Herzegowina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesch', + 'BE' => 'Belgien', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgarien', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint-Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivien', + 'BQ' => 'Bonaire, Sint Eustatius und Saba', + 'BR' => 'Brasilien', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvetinsel', + 'BW' => 'Botsuana', + 'BY' => 'Weißrussland', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Kokosinseln (Keelinginseln)', + 'CD' => 'Kongo, Demokratische Republik', + 'CF' => 'Zentralafrikanische Republik', + 'CG' => 'Kongo', + 'CH' => 'Schweiz', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cookinseln', + 'CL' => 'Chile', + 'CM' => 'Kamerun', + 'CN' => 'China', + 'CO' => 'Kolumbien', + 'CR' => 'Costa Rica', + 'CU' => 'Kuba', + 'CV' => 'Kap Verde', + 'CW' => 'Curaçao', + 'CX' => 'Weihnachtsinsel', + 'CY' => 'Zypern', + 'CZ' => 'Tschechische Republik', + 'DE' => 'Deutschland', + 'DJ' => 'Dschibuti', + 'DK' => 'Dänemark', + 'DM' => 'Dominica', + 'DO' => 'Dominikanische Republik', + 'DZ' => 'Algerien', + 'EC' => 'Ecuador', + 'EE' => 'Estland', + 'EG' => 'Ägypten', + 'EH' => 'Westsahara', + 'ER' => 'Eritrea', + 'ES' => 'Spanien', + 'ET' => 'Äthiopien', + 'FI' => 'Finnland', + 'FJ' => 'Fidschi', + 'FK' => 'Falkland-Inseln (Malvinen)', + 'FM' => 'Mikronesien, Föderierte Staaten von', + 'FO' => 'Färöer Inseln', + 'FR' => 'Frankreich', + 'GA' => 'Gabun', + 'GB' => 'Vereinigtes Königreich', + 'GD' => 'Grenada', + 'GE' => 'Georgien', + 'GF' => 'Französisch-Guayana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Grönland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Äquatorialguinea', + 'GR' => 'Griechenland', + 'GS' => 'Südgeorgien und die Südlichen Sandwichinseln', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hongkong', + 'HM' => 'Heard- und McDonaldinseln', + 'HN' => 'Honduras', + 'HR' => 'Kroatien', + 'HT' => 'Haiti', + 'HU' => 'Ungarn', + 'ID' => 'Indonesien', + 'IE' => 'Irland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'Indien', + 'IO' => 'Britisches Territorium im Indischen Ozean', + 'IQ' => 'Irak', + 'IR' => 'Iran, Islamische Republik', + 'IS' => 'Island', + 'IT' => 'Italien', + 'JE' => 'Jersey', + 'JM' => 'Jamaika', + 'JO' => 'Jordanien', + 'JP' => 'Japan', + 'KE' => 'Kenia', + 'KG' => 'Kirgistan', + 'KH' => 'Kambodscha', + 'KI' => 'Kiribati', + 'KM' => 'Komoren', + 'KN' => 'St. Kitts und Nevis', + 'KP' => "Nordkorea", + 'KR' => 'Südkorea', + 'KW' => 'Kuwait', + 'KY' => 'Kaiman-Inseln', + 'KZ' => 'Kasachstan', + 'LA' => "Laos, Demokratische Volksrepublik", + 'LB' => 'Libanon', + 'LC' => 'St. Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Litauen', + 'LU' => 'Luxemburg', + 'LV' => 'Lettland', + 'LY' => 'Libyen', + 'MA' => 'Marokko', + 'MC' => 'Monaco', + 'MD' => 'Moldawien, Republik', + 'ME' => 'Montenegro', + 'MF' => 'St. Martin (französischer Teil)', + 'MG' => 'Malagasy', + 'MH' => 'Marshallinseln', + 'MK' => 'Mazedonien', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolei', + 'MO' => 'Macao', + 'MP' => 'Nördliche Marianen', + 'MQ' => 'Martinique', + 'MR' => 'Mauretanien', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Malediven', + 'MW' => 'Malawi', + 'MX' => 'Mexiko', + 'MY' => 'Malaysia', + 'MZ' => 'Mosambik', + 'N/A' => 'Nicht anwendbar (lokale IP…)', + 'NA' => 'Namibia', + 'NC' => 'Neukaledonien', + 'NE' => 'Niger', + 'NF' => 'Norfolkinsel', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Niederlande', + 'NO' => 'Norwegen', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Neuseeland', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Französisch-Polynesien', + 'PG' => 'Papua-Neuguinea', + 'PH' => 'Philippinen', + 'PK' => 'Pakistan', + 'PL' => 'Polen', + 'PM' => 'Saint-Pierre und Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Staat Palästina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Katar', + 'RE' => 'Réunion', + 'RO' => 'Rumänien', + 'RS' => 'Serbien', + 'RU' => 'Russische Föderation', + 'RW' => 'Ruanda', + 'SA' => 'Saudi-Arabien', + 'SB' => 'Salomonen', + 'SC' => 'Seychellen', + 'SD' => 'Sudan', + 'SE' => 'Schweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension und Tristan da Cunha', + 'SI' => 'Slowenien', + 'SJ' => 'Svalbard und Jan Mayen', + 'SK' => 'Slowakei', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'Süd - Sudan', + 'ST' => 'São Tomé und Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'St. Martin (Holländischer Teil)', + 'SY' => 'Syrien', + 'SZ' => 'Swaziland', + 'TC' => 'Turks- und Caicosinseln', + 'TD' => 'Tschad', + 'TF' => 'Französische Süd- und Antarktisgebiete', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tadschikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunesien', + 'TO' => 'Tonga', + 'TR' => 'Türkei', + 'TT' => 'Trinidad und Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Provinz Chinas', + 'TZ' => 'Tansania, Vereinigte Republik', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'Kleinere Inselbesitzungen der Vereinigten Staaten', + 'US' => 'Vereinigte Staaten von Amerika', + 'UY' => 'Uruguay', + 'UZ' => 'Usbekistan', + 'VA' => 'Heiliger Stuhl (Vatikanstadt)', + 'VC' => 'St. Vincent und die Grenadinen', + 'VE' => 'Venezuela, Bolivarische Republik', + 'VG' => 'Britische Jungferninseln', + 'VI' => 'Amerikanische Jungferninseln', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis und Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Mayotte', + 'ZA' => 'Südafrika', + 'ZM' => 'Sambia', + 'ZW' => 'Simbabwe', +]; diff --git a/modules/Admin/Language/de/Dashboard.php b/modules/Admin/Language/de/Dashboard.php new file mode 100644 index 00000000..2b539a71 --- /dev/null +++ b/modules/Admin/Language/de/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin-Dashboard', + 'welcome_message' => 'Willkommen im Administrationsbereich!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Kein veröffentlichter Podcast', + 'last_published' => 'Zuletzt veröffentlicht am {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Folgen', + 'not_found' => 'Keine veröffentlichte Episode', + 'last_published' => 'Zuletzt veröffentlicht am {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Speicher', + 'subtitle' => '{totalUploaded} von {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/de/Episode.php b/modules/Admin/Language/de/Episode.php new file mode 100644 index 00000000..15009e31 --- /dev/null +++ b/modules/Admin/Language/de/Episode.php @@ -0,0 +1,225 @@ + 'Staffel {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Folge {episodeNumber}', + 'number_abbr' => 'F. {episodeNumber}', + 'season_episode' => 'Staffel {seasonNumber} Folge {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}F{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# Kommentar} + other {# Kommentare} + }', + 'all_podcast_episodes' => 'Alle Podcast-Episoden', + 'back_to_podcast' => 'Zurück zum Podcast', + 'edit' => 'Bearbeiten', + 'preview' => 'Vorschau', + 'publish' => 'Veröffentllichen', + 'publish_edit' => 'Veröffentlichung bearbeiten', + 'publish_date_edit' => 'Veröffentlichungsdatum bearbeiten', + 'unpublish' => 'Veröffentlichung zurücknehmen', + 'publish_error' => 'Folge ist bereits veröffentlicht.', + 'publish_edit_error' => 'Folge ist bereits veröffentlicht.', + 'publish_cancel_error' => 'Folge ist bereits veröffentlicht.', + 'publish_date_edit_error' => 'Die Folge wurde noch nicht veröffentlicht, Sie können das Veröffentlichungsdatum nicht bearbeiten.', + 'publish_date_edit_future_error' => 'Das Veröffentlichungsdatum der Folge kann nur auf ein vergangenes Datum gesetzt werden! Wenn Sie es neu planen möchten, heben Sie die Veröffentlichung zuerst auf.', + 'publish_date_edit_success' => 'Das Veröffentlichungsdatum der Folge wurde erfolgreich aktualisiert!', + 'unpublish_error' => 'Folge ist nicht veröffentlicht.', + 'delete' => 'Löschen', + 'go_to_page' => 'Gehe zu Seite', + 'create' => 'Folge hinzufügen', + 'publication_status' => [ + 'published' => 'Veröffentlicht', + 'with_podcast' => 'Veröffentlicht', + 'scheduled' => 'Geplant', + 'not_published' => 'Nicht veröffentlicht', + ], + 'with_podcast_hint' => 'Wird zeitgleich mit dem Podcast veröffentlicht', + 'list' => [ + 'search' => [ + 'placeholder' => 'Suche nach einer Episode', + 'clear' => 'Suche zurücksetzen', + 'submit' => 'Suche', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# Folge} + other {# Folgen} + }', + 'episode' => 'Folge', + 'visibility' => 'Sichtbarkeit', + 'downloads' => 'Downloads', + 'comments' => 'Kommentar', + 'actions' => 'Aktionen', + ], + 'messages' => [ + 'createSuccess' => 'Folge wurde erfolgreich erstellt!', + 'editSuccess' => 'Folge wurde erfolgreich aktualisiert!', + 'publishSuccess' => '{publication_status, select, + published {Folge erfolgreich veröffentlicht!} + scheduled {Veröffentlichung der Folge erfolgreich geplant!} + with_podcast {Diese Folge wird zeitgleich mit dem Podcast veröffentlicht.} + other {Diese Folge ist nicht veröffentlicht.} + }', + 'publishCancelSuccess' => 'Veröffentlichung der Episode abgebrochen!', + 'unpublishBeforeDeleteTip' => 'Du musst die Episode zurückziehen, bevor du sie löschst.', + 'scheduleDateError' => 'Veröffentlichungsdatum muss gesetzt sein!', + 'deletePublishedEpisodeError' => 'Bitte ziehe die Episode zurück, bevor du sie löschst.', + 'deleteSuccess' => 'Folge erfolgreich gelöscht!', + 'deleteError' => 'Fehler beim Löschen der {type, select, + transcript {Abschrift} + chapters {Kapitel} + image {Cover} + audio {Audio} + other {Medien} + }-Datei dieser Episode.', + 'deleteFileError' => 'Fehler beim Löschen der {type, select, + transcript {Abschrift} + chapters {Kapitel} + image {Cover} + audio {Audio} + other {Medien} + }-Datei {file_key}. Sie können es manuell von der Festplatte entfernen.', + 'sameSlugError' => 'Eine Folge mit dem ausgewählten Slug existiert bereits.', + ], + 'form' => [ + 'file_size_error' => + 'Die Dateigröße ist zu groß! Maximale Größe ist {0}. Erhöhe `memory_limit`, `upload_max_filesize` und `post_max_size` Werte in Deiner PHP-Konfigurationsdatei und starte dann den Webserver neu, um Deine Datei hochzuladen.', + 'audio_file' => 'Audiodatei', + 'audio_file_hint' => 'Wähle eine .mp3- oder .m4a-Audiodatei.', + 'info_section_title' => 'Episodeninfo', + 'cover' => 'Episoden-Cover', + 'cover_hint' => + 'Wenn Du kein Cover festlegst, wird stattdessen das Podcast-Cover verwendet.', + 'cover_size_hint' => 'Das Cover muss quadratisch und mindestens 1400px breit und hoch sein.', + 'title' => 'Titel', + 'title_hint' => + 'Nutze einen klaren und einprägsamen Episodennamen. Gib hier nicht die Episoden- oder Staffelnummern an.', + 'permalink' => 'Permalink', + 'season_number' => 'Staffel', + 'episode_number' => 'Folge', + 'type' => [ + 'label' => 'Typ', + 'full' => 'Komplett', + 'full_hint' => 'Vollständiger Inhalt (die Episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Kurze bewerbende Inhalte, die eine Vorschau der aktuellen Sendung darstellen', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Zusätzliche Inhalte für die Sendung (zum Beispiel hinter den Kulissen, Informationen oder Interviews mit dem Team) oder übergreifende Promotionsinhalte für eine andere Show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Diese Episode darf nur für Premium-Abonnenten zugänglich sein', + 'parental_advisory' => [ + 'label' => 'Hinweis für Erziehungsberechtigte', + 'hint' => 'Enthält die Folge anstößige Inhalte?', + 'undefined' => 'undefiniert', + 'clean' => 'Sauber', + 'explicit' => 'Anstößig', + ], + 'show_notes_section_title' => 'Notizen anzeigen', + 'show_notes_section_subtitle' => + 'Bis zu 4000 Zeichen, sei klar und präzise. Die Shownotes helfen potentiellen Zuhörern beim Finden der Episode.', + 'description' => 'Beschreibung', + 'description_footer' => 'Beschreibungsfußzeile', + 'description_footer_hint' => + 'Dieser Text wird am Ende jeder Episodenbeschreibung hinzugefügt, es ist ein guter Ort, um zum Beispiel Ihre sozialen Links einzufügen.', + 'additional_files_section_title' => 'Zusätzliche Dateien', + 'additional_files_section_subtitle' => + 'Diese Dateien könnten von anderen Plattformen genutzt werden, um eine bessere Nutzererfahrung zu bieten. Weitere Informationen finden Sie unter {podcastNamespaceLink}.', + 'location_section_title' => 'Standort', + 'location_section_subtitle' => 'Über welchen Ort handelt diese Folge?', + 'location_name' => 'Standortname oder Adresse', + 'location_name_hint' => 'Dies kann ein realer oder fiktiver Ort sein', + 'transcript' => 'Transkript (Untertitel)', + 'transcript_hint' => 'Nur .srt oder .vtt sind erlaubt.', + 'transcript_download' => 'Transkript herunterladen', + 'transcript_file' => 'Transkriptdatei (.srt oder .vtt)', + 'transcript_remote_url' => 'Remote-URL für Transkript', + 'transcript_file_delete' => 'Transkriptionsdatei löschen', + 'chapters' => 'Kapitel', + 'chapters_hint' => 'Die Datei muss im JSON Chapters Format sein.', + 'chapters_download' => 'Kapitel herunterladen', + 'chapters_file' => 'Kapiteldatei', + 'chapters_remote_url' => 'Externe URL für Kapiteldatei', + 'chapters_file_delete' => 'Lösche Kapiteldatei', + 'advanced_section_title' => 'Erweiterte Einstellungen', + 'advanced_section_subtitle' => + 'Wenn du RSS-Tags benötigst, die Castopod nicht behandelt, setze diese hier.', + 'custom_rss' => 'Eigene RSS-Tags für die Episode', + 'custom_rss_hint' => 'Dies wird innerhalb des ❬item❭ Tags eingefügt.', + 'block' => 'Episode soll vor öffentlichen Katalogen versteckt werden', + 'block_hint' => + 'Die Episode zeigt oder versteckt den Status: Beim Einschalten dieser Option wird verhindert, dass die Episode in Apple Podcasts, Google Podcasts und alle Apps von Drittanbietern, die Inhalte aus diesen Verzeichnissen ziehen, erscheint. (Nicht garantiert)', + 'submit_create' => 'Folge erstellen', + 'submit_edit' => 'Folge speichern', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Zurück zum Folgen-Dashboard', + 'post' => 'Ankündigungsbeitrag', + 'post_hint' => + "Nachricht schreiben, um die Veröffentlichung der Folge anzukündigen. Die Nachricht wird an alle Follower im Fediversum übertragen und auf der Homepage des Podcasts vorgestellt.", + 'message_placeholder' => 'Nachricht schreiben...', + 'publication_date' => 'Veröffentlichungsdatum', + 'publication_method' => [ + 'now' => 'Jetzt', + 'schedule' => 'Zeitplan', + 'with_podcast' => 'Zusammen mit dem Podcast veröffentlichen', + ], + 'scheduled_publication_date' => 'Geplantes Veröffentlichungsdatum', + 'scheduled_publication_date_clear' => 'Veröffentlichungsdatum löschen', + 'scheduled_publication_date_hint' => + 'Du kannst die Veröffentlichung der Episode planen, indem du ein zukünftiges Veröffentlichungsdatum festlegst. Dieses Feld muss als YYYY-MM-TT HH:mm formatiert werden', + 'submit' => 'Veröffentllichen', + 'submit_edit' => 'Veröffentlichung bearbeiten', + 'cancel_publication' => 'Veröffentlichung abbrechen', + 'message_warning' => 'Du hast keine Nachricht für deinen Ankündigungsbeitrag geschrieben!', + 'message_warning_hint' => 'Eine Nachricht zu haben erhöht das soziale Engagement, was zu einer besseren Sichtbarkeit für Ihre Episode führt.', + 'message_warning_submit' => 'Trotzdem veröffentlichen', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Neues Veröffentlichungsdatum', + 'new_publication_date_hint' => 'Muss auf ein vergangenes Datum gesetzt werden.', + 'submit' => 'Veröffentlichungsdatum bearbeiten', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Das Zurückziehen dieser Episode löscht alle damit verbundenen Kommentare und Beiträge und entferne sie aus dem RSS-Feed des Podcasts.", + 'understand' => 'Ich verstehe, ich möchte die Episode zurückziehen', + 'submit' => 'Zurückziehen', + ], + 'delete_form' => [ + 'disclaimer' => + "Das Löschen der Episode wird auch alle verknüpften Mediendateien, Kommentare, Videoclips und Soundbites löschen.", + 'understand' => 'Ich verstehe, ich möchte die Folge löschen', + 'submit' => 'Löschen', + ], + 'embed' => [ + 'title' => 'Einbettbarer Spieler', + 'label' => + 'Wähle eine Erscheinungsbild-Farbe, kopiere den einbettbaren Spieler in die Zwischenablage und füge ihn dann in die Webseite ein.', + 'clipboard_iframe' => 'Kopiere einbettbaren Spieler in die Zwischenablage', + 'clipboard_url' => 'Adresse in Zwischenablage kopieren', + 'dark' => 'Dunkel', + 'dark-transparent' => 'Dunkel (transparent)', + 'light' => 'Hell', + 'light-transparent' => 'Hell (transparent)', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'Entwurfsmodus', + 'text' => '{publication_status, select, + published {Diese Episode ist noch nicht veröffentlicht.} + scheduled {Diese Episode ist für die Veröffentlichung geplant am {publication_date}.} + with_podcast {Diese Episode wird zur gleichen Zeit wie der Podcast veröffentlicht.} + other {Diese Episode ist noch nicht veröffentlicht.} + }', + 'preview' => 'Vorschau', + ], +]; diff --git a/modules/Admin/Language/de/EpisodeNavigation.php b/modules/Admin/Language/de/EpisodeNavigation.php new file mode 100644 index 00000000..eed85a30 --- /dev/null +++ b/modules/Admin/Language/de/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Seite der Folge anzeigen', + 'dashboard' => 'Folgen-Dashboard', + 'episode-view' => 'Startseite', + 'episode-edit' => 'Folge bearbeiten', + 'episode-persons-manage' => 'Personen verwalten', + 'embed-add' => 'Einbettbarer Spieler', + 'clips' => 'Clips', + 'video-clips-list' => 'Videoclips', + 'video-clips-create' => 'Neuer Videoclip', + 'soundbites-list' => 'Tonschnipsel', + 'soundbites-create' => 'Neuer Tonschnipsel', +]; diff --git a/modules/Admin/Language/de/Fediverse.php b/modules/Admin/Language/de/Fediverse.php new file mode 100644 index 00000000..1c2a060d --- /dev/null +++ b/modules/Admin/Language/de/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Das Konto konnte nicht gefunden werden!', + 'blockActorSuccess' => '{actor} wurde blockiert!', + 'unblockActorSuccess' => 'Benutzer wurde entsperrt!', + 'blockDomainSuccess' => '{domain} wurde blockiert!', + 'unblockDomainSuccess' => '{domain} wurde freigegeben!', + ], + 'blocked_actors' => 'Blockierte Konten', + 'blocked_domains' => 'Blockierte Domains', + 'block_lists_form' => [ + 'handle' => 'Account-Identifikation', + 'handle_hint' => '@username@domain Konto eingeben.', + 'domain' => 'Domain', + 'submit' => 'Blockieren!', + ], + 'list' => [ + 'actor' => 'Konto', + 'domain' => 'Domain', + 'unblock' => 'Freigeben', + ], +]; diff --git a/modules/Admin/Language/de/Home.php b/modules/Admin/Language/de/Home.php new file mode 100644 index 00000000..3c4f5a05 --- /dev/null +++ b/modules/Admin/Language/de/Home.php @@ -0,0 +1,14 @@ + 'Alle Podcasts', + 'no_podcast' => 'Keinen Podcast gefunden', +]; diff --git a/modules/Admin/Language/de/Install.php b/modules/Admin/Language/de/Install.php new file mode 100644 index 00000000..89a8b267 --- /dev/null +++ b/modules/Admin/Language/de/Install.php @@ -0,0 +1,61 @@ + 'Manuelle Konfiguration', + 'manual_config_subtitle' => + '`.env`-Datei mit deinen Einstellungen erstellen und die Seite aktualisieren, um mit der Installation fortzufahren.', + 'form' => [ + 'instance_config' => 'Instanzinformationen', + 'hostname' => 'Hostname', + 'media_base_url' => 'Medien-Basis-URL', + 'media_base_url_hint' => + 'Um optional CDN und/oder einen externen Analysedienst verwenden zu können, müssen die Daten eingegeben werden.', + 'admin_gateway' => 'Admin-Gateway', + 'admin_gateway_hint' => + 'Der Pfad zum Zugriff auf den Admin-Bereich (z.B. https://example.com/cp-admin). Standardmäßig als cp-admin festgelegt. Wir empfehlen, sie aus Sicherheitsgründen zu ändern.', + 'auth_gateway' => 'Auth-Gateway', + 'auth_gateway_hint' => + 'Der Pfad zum Zugriff auf die Authentifizierungsseiten (z. B. https://example.com/cp-auth). Standardmäßig als cp-auth gesetzt. Wir empfehlen, sie aus Sicherheitsgründen zu ändern.', + 'database_config' => 'Datenbankkonfiguration', + 'database_config_hint' => + 'Castopod muss sich mit der MySQL-Datenbank (oder MariaDB) verbinden. Wenn diese erforderlichen Informationen nicht verfügbar sind, wenden Sie sich bitte an Ihren Serveradministrator.', + 'db_hostname' => 'Datenbank Hostname', + 'db_name' => 'Datenbankname', + 'db_username' => 'Datenbankbenutzername', + 'db_password' => 'Datenbankpasswort', + 'db_prefix' => 'Tabellenpräfix', + 'db_prefix_hint' => + "Das Präfix der Castopod-Tabellennamen. Nicht anpassen, wenn du nicht weißt, was damit gemeint ist.", + 'cache_config' => 'Cachekonfiguration', + 'cache_config_hint' => + 'Wählen Sie Ihren bevorzugten Cache-Handler. Standardwert verwenden, wenn Sie nicht wissen, was damit gemeint ist.', + 'cache_handler' => 'Cache-Handler', + 'cacheHandlerOptions' => [ + 'file' => 'Datei', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Weiter', + 'submit' => 'Installation abschließen', + 'create_superadmin' => 'Superadmin Konto erstellen', + 'email' => 'E-Mail', + 'username' => 'Benutzername', + 'password' => 'Passwort', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Superadmin-Account wurde erfolgreich erstellt. Anmelden, um loszulegen!', + 'databaseConnectError' => + 'Castopod konnte keine Verbindung zur Datenbank herstellen. Datenbankkonfiguration bearbeiten und erneut versuchen.', + 'writeError' => + "Konnte die `.env`-Datei nicht erstellen/schreiben. Sie muss manuell erstellt werden, indem dem `.env.example` Template im Castopod Paket gefolgt wird.", + ], +]; diff --git a/modules/Admin/Language/de/Navigation.php b/modules/Admin/Language/de/Navigation.php new file mode 100644 index 00000000..f7b7b0ba --- /dev/null +++ b/modules/Admin/Language/de/Navigation.php @@ -0,0 +1,44 @@ + 'Seitenleiste ein/aus', + 'go_to_website' => 'Gehe zur Webseite', + 'go_to_admin' => 'Gehe zu Admin', + 'not-authorized' => 'Nicht berechtigt', + 'dashboard' => 'Übersicht', + 'admin' => 'Startseite', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Alle Podcasts', + 'podcast-create' => 'Neuer Podcast', + 'all-podcast-imports' => 'Alle Podcast-Importe', + 'podcast-imports-add' => 'Podcast importieren', + 'persons' => 'Mitwirkende', + 'person-list' => 'Alle Mitwirkenden', + 'person-create' => 'Neuer Mitwirkender', + 'fediverse' => 'Fediversum', + 'fediverse-blocked-actors' => 'Blockierte Konten', + 'fediverse-blocked-domains' => 'Blockierte Domains', + 'users' => 'Benutzer', + 'user-list' => 'Alle Benutzer', + 'user-create' => 'Neuer Benutzer', + 'pages' => 'Seiten', + 'page-list' => 'Alle Seiten', + 'page-create' => 'Neue Seite', + 'settings' => 'Einstellungen', + 'settings-general' => 'Allgemein', + 'settings-theme' => 'Erscheinungsbild', + 'admin-about' => 'Über', + 'account' => [ + 'my-account' => 'Mein Konto', + 'change-password' => 'Passwort ändern', + 'logout' => 'Abmelden', + ], +]; diff --git a/modules/Admin/Language/de/Notifications.php b/modules/Admin/Language/de/Notifications.php new file mode 100644 index 00000000..88439bb4 --- /dev/null +++ b/modules/Admin/Language/de/Notifications.php @@ -0,0 +1,19 @@ + 'Benachrichtigungen', + 'reply' => '{actor_username} hat auf Ihren Beitrag geantwortet', + 'favourite' => '{actor_username} hat Ihren Beitrag favorisiert', + 'reblog' => '{actor_username} hat Ihren Beitrag geteilt', + 'follow' => '{actor_username} folgt Ihnen jetzt', + 'no_notifications' => 'Keine Benachrichtigungen', + 'mark_all_as_read' => 'Alle als gelesen markieren', +]; diff --git a/modules/Admin/Language/de/Page.php b/modules/Admin/Language/de/Page.php new file mode 100644 index 00000000..801ff2e7 --- /dev/null +++ b/modules/Admin/Language/de/Page.php @@ -0,0 +1,30 @@ + 'Zurück zur Startseite', + 'page' => 'Seite', + 'all_pages' => 'Alle Seiten', + 'create' => 'Neue Seite', + 'go_to_page' => 'Gehe zur Seite', + 'edit' => 'Seite bearbeiten', + 'delete' => 'Seite löschen', + 'form' => [ + 'title' => 'Titel', + 'permalink' => 'Permalink', + 'content' => 'Inhalt', + 'submit_create' => 'Seite erstellen', + 'submit_edit' => 'Speichern', + ], + 'messages' => [ + 'createSuccess' => 'Die Seite „{pageTitle}“ wurde erfolgreich erstellt!', + 'editSuccess' => 'Die Seite wurde erfolgreich aktualisiert!', + ], +]; diff --git a/modules/Admin/Language/de/Pager.php b/modules/Admin/Language/de/Pager.php new file mode 100644 index 00000000..54c96cbe --- /dev/null +++ b/modules/Admin/Language/de/Pager.php @@ -0,0 +1,21 @@ + 'Seiten-Navigation', + 'first' => 'Erste Seite', + 'previous' => 'Vorherige', + 'next' => 'Nächste', + 'last' => 'Letzte Seite', + 'older' => 'Älter', + 'newer' => 'Neuer', + 'invalidTemplate' => '{0} ist kein gültiges Pager Template.', + 'invalidPaginationGroup' => '{0} ist keine gültige Paginierungs-Gruppe.', +]; diff --git a/modules/Admin/Language/de/Person.php b/modules/Admin/Language/de/Person.php new file mode 100644 index 00000000..a9287867 --- /dev/null +++ b/modules/Admin/Language/de/Person.php @@ -0,0 +1,65 @@ + 'Personen', + 'all_persons' => 'Alle Personen', + 'no_person' => 'Niemanden gefunden!', + 'create' => 'Eine neue Person anlegen', + 'view' => 'Person anzeigen', + 'edit' => 'Person bearbeiten', + 'delete' => 'Person löschen', + 'messages' => [ + 'createSuccess' => 'Person wurde erfolgreich erstellt!', + 'editSuccess' => 'Person wurde erfolgreich aktualisiert!', + 'deleteSuccess' => 'Person wurde entfernt!', + ], + 'form' => [ + 'avatar' => 'Profilbild', + 'avatar_size_hint' => + 'Das Profilbild muss quadratisch und mindestens 400px breit und hoch sein.', + 'full_name' => 'Vollständiger Name', + 'full_name_hint' => 'Dies ist der vollständige Name oder der Alias der Person.', + 'unique_name' => 'Eindeutiger Name', + 'unique_name_hint' => 'Verwendet für URLs', + 'information_url' => 'Informations-URL', + 'information_url_hint' => + 'URL auf eine Seite mit Informationen über eine Person, wie eine Homepage, oder eine Profilseite eines anderen Anbieters.', + 'submit_create' => 'Eine neue Person anlegen', + 'submit_edit' => 'Person speichern', + ], + 'podcast_form' => [ + 'title' => 'Personen verwalten', + 'add_section_title' => 'Personen zu diesem Podcast hinzufügen', + 'add_section_subtitle' => 'Sie können mehrere Personen und Rollen wählen.', + 'persons' => 'Personen', + 'persons_hint' => + 'Es können eine oder mehrere Personen mit der gleichen Rolle ausgewählt werden. Die Personen müssen zuerst erstellt werden.', + 'roles' => 'Rollen', + 'roles_hint' => + 'Es können sowohl keine, eine als auch mehrere Rollen für eine Person ausgewählt werden.', + 'submit_add' => 'Person:en hinzufügen', + 'remove' => 'Entfernen', + ], + 'episode_form' => [ + 'title' => 'Personen verwalten', + 'add_section_title' => 'Personen zu dieser Folge hinzufügen', + 'add_section_subtitle' => 'Es können mehrere Personen und Rollen ausgewählt werden.', + 'persons' => 'Personen', + 'persons_hint' => + 'Es können eine oder mehrere Personen mit der gleichen Rolle ausgewählt werden. Die Personen müssen zuerst erstellt werden.', + 'roles' => 'Rollen', + 'roles_hint' => + 'Es können sowohl keine, eine als auch mehrere Rollen für eine Person ausgewählt werden.', + 'submit_add' => 'Person:en hinzufügen', + 'remove' => 'Entfernen', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/de/Platforms.php b/modules/Admin/Language/de/Platforms.php new file mode 100644 index 00000000..41751316 --- /dev/null +++ b/modules/Admin/Language/de/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcast-Plattformen', + 'social' => 'Soziale Medien', + 'funding' => 'Finanzierungslinks', + ], + 'website' => 'Webseite', + 'home_url' => 'Gehe zu {platformName} Webseite', + 'register' => 'Registrieren', + 'submit_url' => 'Sende deinen Podcast an {platformName}', + 'your_link' => 'Dein Link', + 'your_id' => [ + 'podcasting' => 'Deine ID', + 'social' => 'Deine ID', + 'funding' => 'Deine CTA', + ], + 'your_cta' => 'Dein Aufruf zur Aktion', + 'visible' => 'Auf Podcast-Homepage anzeigen?', + 'on_embed' => 'Auf einbettbarem Player anzeigen?', + 'remove' => 'Entferne {platformName}', + 'submit' => 'Speichern', + 'messages' => [ + 'updateSuccess' => 'Plattform-Links wurden erfolgreich aktualisiert!', + 'removeLinkSuccess' => 'Der Plattform-Link wurde entfernt.', + 'removeLinkError' => + 'Der Plattform-Link konnte nicht entfernt werden. Versuche es erneut.', + ], + 'description' => [ + 'podcasting' => 'Die Podcast-ID auf dieser Plattform', + 'social' => 'Die Podcast-Account-ID auf dieser Plattform', + 'funding' => 'Nachricht zum Handlungsaufruf', + ], +]; diff --git a/modules/Admin/Language/de/Podcast.php b/modules/Admin/Language/de/Podcast.php new file mode 100644 index 00000000..d2165791 --- /dev/null +++ b/modules/Admin/Language/de/Podcast.php @@ -0,0 +1,330 @@ + 'Alle Podcasts', + 'no_podcast' => 'Kein Podcast gefunden!', + 'create' => 'Podcast erstellen', + 'import' => 'Podcast importieren', + 'all_imports' => 'Podcast-Importe', + 'new_episode' => 'Neue Folge', + 'view' => 'Podcast ansehen', + 'edit' => 'Podcast bearbeiten', + 'publish' => 'Podcast veröffentlichen', + 'publish_edit' => 'Veröffentlichung bearbeiten', + 'delete' => 'Podcast löschen', + 'see_episodes' => 'Episoden ansehen', + 'see_contributors' => 'Mitwirkende anzeigen', + 'monetization_other' => 'Sonstige Monetarisierung', + 'go_to_page' => 'Gehe zur Seite', + 'latest_episodes' => 'Neueste Folgen', + 'see_all_episodes' => 'Alle Folgen anzeigen', + 'draft' => 'Entwurf', + 'messages' => [ + 'createSuccess' => 'Podcast erfolgreich erstellt!', + 'editSuccess' => 'Der Podcast wurde erfolgreich aktualisiert!', + 'importSuccess' => 'Der Podcast wurde erfolgreich importiert!', + 'deleteSuccess' => 'Podcast @{podcast_handle} erfolgreich gelöscht!', + 'deletePodcastMediaError' => 'Fehler beim Löschen des Podcast-{type, select, + cover {Covers} + banner {Banners} + other {Media} + }.', + 'deleteEpisodeMediaError' => 'Fehler beim Löschen {type, select, + transcript {der Abschrift} + chapters {der Kapitel} + image {des Covers} + audio {der Audio} + other {der Medien} + } von Episode {episode_slug}.', + 'deletePodcastMediaFolderError' => 'Fehler beim Löschen des Podcast-Medienordners {folder_path}. Sie können ihn manuell von der Festplatte löschen.', + 'podcastFeedUpdateSuccess' => 'Erfolgreiche Aktualisierung: {number_of_new_episodes, plural, + one {# Episode wurde} + other {# Episoden wurden} + } zum Podcast hinzugefügt!', + 'podcastFeedUpToDate' => 'Der Podcast ist bereits auf dem neuesten Stand.', + 'publishError' => 'Dieser Podcast ist entweder bereits veröffentlicht oder zur Veröffentlichung geplant.', + 'publishEditError' => 'Dieser Podcast ist nicht zur Veröffentlichung geplant.', + 'publishCancelSuccess' => 'Veröffentlichung des Podcasts erfolgreich abgebrochen!', + 'scheduleDateError' => 'Veröffentlichungsdatum muss gesetzt sein!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast-Identität', + 'identity_section_subtitle' => 'Diese Felder erlauben es dir, Aufmerksamkeit zu bekommen.', + 'fediverse_section_title' => 'Fediverse-Identität', + + 'cover' => 'Podcast-Cover', + 'cover_size_hint' => 'Das Cover muss quadratisch und mindestens 1400px breit und hoch sein.', + 'banner' => 'Podcast-Banner', + 'banner_size_hint' => 'Der Banner muss ein 3:1-Verhältnis haben und mindestens 1500px breit sein.', + 'banner_delete' => 'Podcast-Banner löschen', + 'title' => 'Titel', + 'handle' => 'Identifikator', + 'handle_hint' => + 'Wird genutzt, um den Podcast zu identifizieren. Großbuchstaben, Kleinbuchstaben, Zahlen und Unterstriche sind erlaubt.', + 'type' => [ + 'label' => 'Typ', + 'episodic' => 'Episodisch', + 'episodic_hint' => 'Wenn Folgen ohne bestimmte Reihenfolge abgespielt werden sollen. Neueste Folgen werden zuerst angezeigt.', + 'serial' => 'Seriell', + 'serial_hint' => 'Wenn Episoden in sequenzieller Reihenfolge konsumiert werden sollen. Episoden werden in numerischer Reihenfolge angezeigt.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Beschreibt einen Feed für eine Podcast-Show.', + 'music' => 'Musik', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Hörbuch', + 'audiobook_hint' => 'Spezifische Arten von Audio mit einem Eintrag pro Feed, oder wenn Elemente Kapitel innerhalb des Buches darstellen.', + ], + 'description' => 'Beschreibung', + 'classification_section_title' => 'Klassifikation', + 'classification_section_subtitle' => + 'Dieser Bereich wird die Zuhörer und den Wettbewerb beeinflussen.', + 'language' => 'Sprache', + 'category' => 'Kategorie', + 'category_placeholder' => 'Kategorie wählen...', + 'other_categories' => 'Andere Kategorien', + 'parental_advisory' => [ + 'label' => 'Hinweis an Eltern', + 'hint' => 'Enthält die Folge anstößige Inhalte?', + 'undefined' => 'nicht definiert', + 'clean' => 'Sauber', + 'explicit' => 'Anstößig', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Wer verwaltet den Podcast?', + 'owner_name' => 'Eigentümer', + 'owner_name_hint' => + 'Nur für administrative Nutzung. Sichtbar im öffentlichen RSS-Feed.', + 'owner_email' => 'E-Mail des Eigentümers', + 'owner_email_hint' => + 'Wird von den meisten Plattformen verwendet werden, um den Podcast-Besitz zu überprüfen. Sichtbar im öffentlichen RSS-Feed.', + 'is_owner_email_removed_from_feed' => 'Entferne die Eigentümer-E-Mail aus dem öffentlichen RSS-Feed', + 'is_owner_email_removed_from_feed_hint' => 'Möglicherweise müssen Sie die E-Mail vorübergehend freigeben, damit ein Verzeichnis Ihren Podcast-Besitz verifizieren kann.', + 'publisher' => 'Herausgeber', + 'publisher_hint' => + 'Die Gruppe, die für die Erstellung des Podcasts verantwortlich ist. Oft bezogen auf die Muttergesellschaft oder das Netzwerk eines Podcasts. Dieses Feld wird manchmal als \'Autor\' bezeichnet.', + 'copyright' => 'Urheberrecht', + 'location_section_title' => 'Standort', + 'location_section_subtitle' => 'Um welchen Ort geht es in diesem Podcast?', + 'location_name' => 'Standortname oder Adresse', + 'location_name_hint' => 'Dies kann ein echter oder ein fiktiver Ort sein', + 'monetization_section_title' => 'Monetarisierung', + 'monetization_section_subtitle' => + 'Geld dank der Zuhörer verdienen.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episoden müssen standardmäßig als Premium festgelegt werden', + 'premium_by_default_hint' => 'Podcast-Episoden werden standardmäßig als Premium markiert. Sie können dennoch einzelne Episoden, Trailer oder Boni als öffentlich festlegen.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Besuche dein OP3-Dashboard (externer Link)', + 'op3_hint' => 'Werten Sie Ihre Analysedaten mit OP3 auf, einem quelloffenen und vertrauenswürdigen Analysedienst eines Drittanbieters. Teilen, validieren und vergleichen Sie Ihre Analysedaten in dem offenen Podcast-Ökosystem.', + 'op3_enable' => 'OP3-Analysedienst aktivieren', + 'op3_enable_hint' => 'Aus Sicherheitsgründen werden die Analysedaten von Premium-Episoden nicht mit OP3 geteilt.', + 'payment_pointer' => 'Zahlungsadresse (Payment Pointer) für Web-Monetarisierung', + 'payment_pointer_hint' => + 'Hier erhalten Sie dank Monetarisierung Geld', + 'advanced_section_title' => 'Erweiterte Einstellungen', + 'advanced_section_subtitle' => + 'Wenn RSS-Tags benötigt werden, die Castopod nicht verwendet, können diese hier gesetzt werden.', + 'custom_rss' => 'Eigene RSS-Tags für den Podcast', + 'custom_rss_hint' => 'Dies wird innerhalb des ❬channel❭ Tags eingefügt.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Neue Feed-URL', + 'new_feed_url_hint' => 'Benutzen Sie dieses Feld, wenn Sie zu einer anderen Domain oder Podcast-Plattform wechseln. Standardmäßig wird der Wert auf die aktuelle RSS URL gesetzt, wenn der Podcast importiert wird.', + 'old_feed_url' => 'Alte Feed-URL', + 'partnership' => 'Partnerschaft:en', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link', + 'partner_image_url' => 'Bildadresse', + 'partner_id_hint' => 'Ihre eigene Partner-ID', + 'partner_link_url_hint' => 'Die generische Partnerlink-Adresse', + 'partner_image_url_hint' => 'Die generische Partnerbild-Adresse', + 'block' => 'Podcast soll vor öffentlichen Katalogen versteckt werden', + 'block_hint' => + 'Der Podcast zeigt oder versteckt den Status: Beim Einschalten dieser Option wird verhindert, dass der Podcast in Apple Podcasts, Google Podcasts und alle Apps von Drittanbietern, die Inhalte aus diesen Verzeichnissen ziehen, erscheint. (Ohne Garantie!)', + 'complete' => 'Der Podcast wird keine neuen Folgen erhalten', + 'lock' => 'Schütze den Podcast davor kopiert zu werden', + 'lock_hint' => + 'Der Zweck ist es, anderen Podcast-Plattformen mitzuteilen, ob sie diesen Feed importieren dürfen. "Ja" bedeutet, dass jeder Versuch, diesen Feed in eine neue Plattform zu importieren, abgelehnt wird.', + 'submit_create' => 'Podcast erstellen', + 'submit_edit' => 'Podcast speichern', + ], + 'category_options' => [ + 'uncategorized' => 'unkategorisiert', + 'arts' => 'Kunst', + 'business' => 'Geschäftliches', + 'comedy' => 'Comedy', + 'education' => 'Bildung', + 'fiction' => 'Fiktion', + 'government' => 'Regierung', + 'health_and_fitness' => 'Gesundheit & Fitness', + 'history' => 'Geschichte', + 'kids_and_family' => 'Kinder & Familie', + 'leisure' => 'Freizeit', + 'music' => 'Musik', + 'news' => 'Nachrichten', + 'religion_and_spirituality' => 'Religion & Spiritualität', + 'science' => 'Wissenschaft', + 'society_and_culture' => 'Gesellschaft & Kultur', + 'sports' => 'Sport', + 'technology' => 'Technologie', + 'true_crime' => 'Wahres Verbrechen', + 'tv_and_film' => 'TV & Filme', + 'books' => 'Bücher', + 'design' => 'Design', + 'fashion_and_beauty' => 'Mode & Schönheit', + 'food' => 'Essen', + 'performing_arts' => 'Darstellende Kunst', + 'visual_arts' => 'Visuelle Kunst', + 'careers' => 'Karriere', + 'entrepreneurship' => 'Unternehmertum', + 'investing' => 'Investment', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Gemeinnützigkeit', + 'comedy_interviews' => 'Comedy-Interviews', + 'improv' => 'Improvisation', + 'stand_up' => 'Stand-Up', + 'courses' => 'Kurse', + 'how_to' => 'So geht\'s', + 'language_learning' => 'Sprachenlernen', + 'self_improvement' => 'Weiterbildung', + 'comedy_fiction' => 'Komödie Fiktion', + 'drama' => 'Drama', + 'science_fiction' => 'Science-Fiction', + 'alternative_health' => 'Alternative Gesundheit', + 'fitness' => 'Fitness', + 'medicine' => 'Medizin', + 'mental_health' => 'Mentale Gesundheit', + 'nutrition' => 'Ernährung', + 'sexuality' => 'Sexualität', + 'education_for_kids' => 'Bildung für Kinder', + 'parenting' => 'Erziehung', + 'pets_and_animals' => 'Haustiere & Tiere', + 'stories_for_kids' => 'Geschichten für Kinder', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Autos', + 'aviation' => 'Luftfahrt', + 'crafts' => 'Handwerk', + 'games' => 'Spiele', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Heim & Garten', + 'video_games' => 'Videospiele', + 'music_commentary' => 'Musikkommentar', + 'music_history' => 'Musikgeschichte', + 'music_interviews' => 'Musikinterviews', + 'business_news' => 'Wirtschaftsnachrichten', + 'daily_news' => 'Nachrichten', + 'entertainment_news' => 'Unterhaltung', + 'news_commentary' => 'Nachrichtenkommentar', + 'politics' => 'Politik', + 'sports_news' => 'Sport', + 'tech_news' => 'Technik', + 'buddhism' => 'Buddhismus', + 'christianity' => 'Christentum', + 'hinduism' => 'Hinduismus', + 'islam' => 'Islam', + 'judaism' => 'Judentum', + 'religion' => 'Religion', + 'spirituality' => 'Spiritualität', + 'astronomy' => 'Astronomie', + 'chemistry' => 'Chemie', + 'earth_sciences' => 'Erdkunde', + 'life_sciences' => 'Lebenswissenschaften', + 'mathematics' => 'Mathematik', + 'natural_sciences' => 'Naturwissenschaft', + 'nature' => 'Natur', + 'physics' => 'Physik', + 'social_sciences' => 'Sozialwissenschaften', + 'documentary' => 'Dokumentation', + 'personal_journals' => 'Persönliche Tagebücher', + 'philosophy' => 'Philosophie', + 'places_and_travel' => 'Orte & Reisen', + 'relationships' => 'Beziehungen', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy-Sport', + 'football' => 'American Football', + 'golf' => 'Golf', + 'hockey' => 'Eishockey', + 'rugby' => 'Rugby', + 'running' => 'Laufen', + 'soccer' => 'Fußball', + 'swimming' => 'Schwimmen', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wildnis', + 'wrestling' => 'Ringen', + 'after_shows' => 'After Shows', + 'film_history' => 'Filmgeschichte', + 'film_interviews' => 'Filminterviews', + 'film_reviews' => 'Filmkritiken', + 'tv_reviews' => 'TV-Kritiken', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Zurück zum Podcast-Dashboard', + 'post' => 'Dein Ankündigungsbeitrag', + 'post_hint' => + "Schreiben Sie eine Nachricht, um die Veröffentlichung Ihres Podcasts anzukündigen. Diese Nachricht wird auf der Homepage des Podcasts erscheinen.", + 'message_placeholder' => 'Schreiben Sie Ihre Nachricht…', + 'submit' => 'Veröffentlichen', + 'publication_date' => 'Veröffentlichungsdatum', + 'publication_method' => [ + 'now' => 'Jetzt', + 'schedule' => 'Planen', + ], + 'scheduled_publication_date' => 'Geplantes Veröffentlichungsdatum', + 'scheduled_publication_date_hint' => + 'Du kannst die Veröffentlichung des Podcasts planen, indem du ein zukünftiges Veröffentlichungsdatum festlegst. Dieses Feld muss als YYYY-MM-TT HH:mm formatiert werden', + 'submit_edit' => 'Veröffentlichung bearbeiten', + 'cancel_publication' => 'Veröffentlichung abbrechen', + 'message_warning' => 'Sie haben keinen Text für Ihren Ankündigungsbeitrag geschrieben!', + 'message_warning_hint' => 'Eine Nachricht erhöht das soziale Engagement, was zu einer besseren Sichtbarkeit des Podcasts führt.', + 'message_warning_submit' => 'Dennoch veröffentlichen', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'Entwurfsmodus', + 'not_published' => 'Dieser Podcast ist noch nicht veröffentlicht.', + 'scheduled' => 'Dieser Podcast ist für eine Veröffentlichung am {publication_date} vorgesehen.', + ], + 'delete_form' => [ + 'disclaimer' => + "Beim Löschen des Podcasts werden alle damit verbundenen Episoden, Mediendateien, Beiträge und Analysen gelöscht. Diese Aktion ist unumkehrbar, Sie können diese danach nicht mehr abrufen.", + 'understand' => 'Ich verstehe, ich möchte, dass der Podcast dauerhaft gelöscht wird', + 'submit' => 'Löschen', + ], + 'by' => 'Von {publisher}', + 'season' => 'Staffel {seasonNumber}', + 'list_of_episodes_year' => '{year} Folgen ({episodeCount})', + 'list_of_episodes_season' => + 'Staffel {seasonNumber} Folgen ({episodeCount})', + 'no_episode' => 'Keine Folge gefunden!', + 'follow' => 'Folgen', + 'followers' => '{numberOfFollowers, plural, + one {# Follower} + other {# Follower} + }', + 'posts' => '{numberOfPosts, plural, + one {# Beitrag} + other {# Beiträge} + }', + 'activity' => 'Aktivitäten', + 'episodes' => 'Folgen', + 'sponsor' => 'Unterstützer', + 'funding_links' => 'Links zur Finanzierung von {podcastTitle}', + 'find_on' => 'Finde {podcastTitle} auf', + 'listen_on' => 'Hören auf', +]; diff --git a/modules/Admin/Language/de/PodcastNavigation.php b/modules/Admin/Language/de/PodcastNavigation.php new file mode 100644 index 00000000..6fa2e17d --- /dev/null +++ b/modules/Admin/Language/de/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Zur Podcast-Seite gehen', + 'rss_feed' => 'RSS-Feed', + 'dashboard' => 'Podcast-Dashboard', + 'podcast-view' => 'Startseite', + 'podcast-edit' => 'Podcast bearbeiten', + 'podcast-persons-manage' => 'Mitwirkende verwalten', + 'podcast-imports' => 'Podcast-Importe', + 'podcast-imports-sync' => 'Feeds synchronisieren', + 'episodes' => 'Folgen', + 'episode-list' => 'Alle Episoden', + 'episode-create' => 'Neue Episoden', + 'analytics' => 'Statistiken', + 'podcast-analytics' => 'Zuhörer-Übersicht', + 'podcast-analytics-webpages' => 'Webseiten-Besuche', + 'podcast-analytics-locations' => 'Standorte', + 'podcast-analytics-unique-listeners' => 'Eindeutige Zuhörer', + 'podcast-analytics-players' => 'Podcast-Player', + 'podcast-analytics-listening-time' => 'Hörzeit', + 'podcast-analytics-time-periods' => 'Zeiträume', + 'monetization' => 'Monetarisierung', + 'subscription-list' => 'Alle Abonnements', + 'subscription-create' => 'Abonnement hinzufügen', + 'contributors' => 'Mitwirkende', + 'contributor-list' => 'Alle Unterstützer', + 'contributor-add' => 'Mitwirkenden hinzufügen', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcast-Apps', + 'platforms-social' => 'Soziale Netzwerke', + 'platforms-funding' => 'Finanzierungslinks', + 'podcast-monetization-other' => 'Andere', +]; diff --git a/modules/Admin/Language/de/Settings.php b/modules/Admin/Language/de/Settings.php new file mode 100644 index 00000000..d046a40e --- /dev/null +++ b/modules/Admin/Language/de/Settings.php @@ -0,0 +1,58 @@ + 'Allgemeine Einstellungen', + 'instance' => [ + 'title' => 'Instanz', + 'site_icon' => 'Webseiten-Icon', + 'site_icon_delete' => 'Lösche Webseiten-Icon', + 'site_icon_hint' => 'Webseiten-Icons sind das, was Sie in Ihren Browser-Tabs, der Lesezeichenleiste und als Verknüpfung auf mobilen Geräten sehen.', + 'site_icon_helper' => 'Das Icon muss quadratisch und mindestens 512px breit und hoch sein.', + 'site_name' => 'Seitenname', + 'site_description' => 'Seitenbeschreibung', + 'submit' => 'Speichern', + 'editSuccess' => 'Die Instanz wurde erfolgreich aktualisiert!', + 'deleteIconSuccess' => 'Das Seiten-Icon wurde erfolgreich entfernt!', + ], + 'images' => [ + 'title' => 'Bilder', + 'subtitle' => 'Hier können Sie alle Bilder auf Basis der hochgeladenen Originale neu erzeugen, wenn Sie feststellen, dass einige Bilder fehlen. Diese Aufgabe kann eine Weile dauern.', + 'regenerate' => 'Bilder neu erzeugen', + 'regenerationSuccess' => 'Alle Bilder wurden erfolgreich neu erzeugt!', + ], + 'housekeeping' => [ + 'title' => 'Systempflege', + 'subtitle' => 'Führt verschiedene Aufgaben zur Systempflege aus. Benutzen Sie diese Funktion, falls Sie jemals Probleme mit Mediendateien oder Datenintegrität haben. Diese Aufgaben können eine Weile dauern.', + 'reset_counts' => 'Zähler zurücksetzen', + 'reset_counts_helper' => 'Diese Option wird alle Datenzähler neu berechnen und zurücksetzen (Anzahl der Follower, Beiträge, Kommentare, …).', + 'rewrite_media' => 'Medien-Metadaten neu schreiben', + 'rewrite_media_helper' => 'Diese Option wird alle überflüssigen Mediendateien löschen und neu erstellen (Bilder, Audiodateien, Transkripte, Kapitel …)', + 'rename_episodes_files' => 'Audiodateien der Episode umbenennen', + 'rename_episodes_files_hint' => 'Diese Option wird alle Audiodateien der Episode mit einer zufälligen Zeichenkette umbenennen. Benutzen Sie diese Option, wenn einer Ihrer privaten Episoden-Links durchsickert, da diese dadurch versteckt werden.', + 'clear_cache' => 'Alle Caches löschen', + 'clear_cache_helper' => 'Diese Option leert den redis-Cache oder beschreibbare/Cache-Dateien.', + 'run' => 'Systempflege starten', + 'runSuccess' => 'Die Systempflege wurde erfolgreich durchgeführt!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Akzentfarbe', + 'accent_section_subtitle' => 'Wähle eine Farbe, um das Erscheinungsbild aller öffentlichen Seiten festzulegen.', + 'pine' => 'Kiefer', + 'crimson' => 'Purpur', + 'amber' => 'Bernstein', + 'lake' => 'Karmesinrot', + 'jacaranda' => 'Palisander', + 'onyx' => 'Onyx', + 'submit' => 'Speichern', + 'setInstanceThemeSuccess' => 'Design wurde erfolgreich aktualisiert!', + ], +]; diff --git a/modules/Admin/Language/de/Soundbite.php b/modules/Admin/Language/de/Soundbite.php new file mode 100644 index 00000000..e8d6782f --- /dev/null +++ b/modules/Admin/Language/de/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite wurde erfolgreich erstellt!', + 'deleteSuccess' => 'Soundbite wurde erfolgreich entfernt!', + ], + 'form' => [ + 'title' => 'Neues Soundbite', + 'soundbite_title' => 'Soundbite-Titel', + 'start_time' => 'Beginne bei', + 'duration' => 'Länge', + 'submit' => 'Soundbite erstellen', + ], + 'play' => 'Soundbite abspielen', + 'stop' => 'Tonschnipsel stoppen', + 'create' => 'Neues Soundbite', + 'delete' => 'Soundbite löschen', +]; diff --git a/modules/Admin/Language/de/Validation.php b/modules/Admin/Language/de/Validation.php new file mode 100644 index 00000000..bae6668c --- /dev/null +++ b/modules/Admin/Language/de/Validation.php @@ -0,0 +1,17 @@ + + '{field} ist entweder kein Bild, oder es ist nicht breit oder hoch genug.', + 'is_image_ratio' => + '{field} ist entweder kein Bild oder nicht das richtige Verhältnis.', + 'is_json' => '{field} enthält ungültiges JSON.', +]; diff --git a/modules/Admin/Language/de/VideoClip.php b/modules/Admin/Language/de/VideoClip.php new file mode 100644 index 00000000..ccf9841b --- /dev/null +++ b/modules/Admin/Language/de/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Videoclips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'wartend', + 'queued_hint' => 'Der Clip wartet auf die Verarbeitung.', + 'pending' => 'ausstehend', + 'pending_hint' => 'Clip wird in Kürze generiert.', + 'running' => 'läuft', + 'running_hint' => 'Clip wird generiert.', + 'failed' => 'fehlgeschlagen', + 'failed_hint' => 'Clip konnte nicht generiert werden: Skriptfehler.', + 'passed' => 'bestanden', + 'passed_hint' => 'Clip wurde erfolgreich erstellt!', + ], + 'clip' => 'Clip', + 'duration' => 'Laufzeit', + ], + 'title' => 'Video-Clip: {videoClipLabel}', + 'download_clip' => 'Clip herunterladen', + 'create' => 'Neuer Videoclip', + 'go_to_page' => 'Zur Clip-Seite gehen', + 'retry' => 'Clip-Generierung wiederholen', + 'delete' => 'Clip löschen', + 'logs' => 'Jobprotokoll', + 'messages' => [ + 'alreadyExistingError' => 'Der Videoclip, den Sie zu erstellen versuchen, existiert bereits!', + 'addToQueueSuccess' => 'Videoclip wurde zur Warteschlange hinzugefügt und wartet darauf, erstellt zu werden!', + 'deleteSuccess' => 'Verlauf wurde erfolgreich gelöscht!', + ], + 'format' => [ + 'landscape' => 'Querformat', + 'portrait' => 'Hochkant', + 'squared' => 'Quadratisch', + ], + 'form' => [ + 'title' => 'Neuer Videoclip', + 'params_section_title' => 'Videoclip-Parameter', + 'clip_title' => 'Clip-Titel', + 'format' => [ + 'label' => 'Wähle ein Format', + 'landscape_hint' => 'Mit einem 16:9 Verhältnis sind Querformat Videos ideal für PeerTube, Youtube und Vimeo.', + 'portrait_hint' => 'Mit einem 9:16 Verhältnis sind Porträt-Videos ideal für TikTok, Youtube-Shorts und Instagram-Stories.', + 'squared_hint' => 'Mit einem 1:1-Verhältnis sind quadratische Videos ideal für Mastodon, Facebook, Twitter und LinkedIn.', + ], + 'theme' => 'Wähle ein Design', + 'start_time' => 'Beginne bei', + 'duration' => 'Laufzeit', + 'trim_start' => 'Startpunkt', + 'trim_end' => 'Ende trimmen', + 'submit' => 'Neuen Clip erstellen', + ], + 'requirements' => [ + 'title' => 'Fehlende Anforderungen', + 'missing' => 'Du hast fehlende Anforderungen. Achte darauf, alle erforderlichen Elemente hinzuzufügen, um ein Video für diese Episode erstellen zu können!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype-Bibliothek für GD', + 'transcript' => 'Transkript-Datei (.srt)', + ], +]; diff --git a/modules/Admin/Language/el/AboutCastopod.php b/modules/Admin/Language/el/AboutCastopod.php new file mode 100644 index 00000000..df1c81f4 --- /dev/null +++ b/modules/Admin/Language/el/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Περί Του Castopod', + 'host_name' => 'Όνομα εξυπηρετητή', + 'version' => 'Έκδοση Castopod', + 'php_version' => 'Έκδοση PHP', + 'os' => 'Λειτουργικό σύστημα', + 'languages' => 'Γλώσσες', + 'update_database' => 'Ενημέρωση Βάσης Δεδομένων', + 'messages' => [ + 'databaseUpdateSuccess' => 'Η βάση δεδομένων είναι ενημερωμένη!', + ], +]; diff --git a/modules/Admin/Language/el/Breadcrumb.php b/modules/Admin/Language/el/Breadcrumb.php new file mode 100644 index 00000000..217f6edb --- /dev/null +++ b/modules/Admin/Language/el/Breadcrumb.php @@ -0,0 +1,57 @@ + 'διαδρομή (Breadcrumb)', + config('Admin') + ->gateway => 'Αρχική σελίδα', + 'podcasts' => 'podcasts', + 'episodes' => 'επεισόδια', + 'subscriptions' => 'συνδρομές', + 'contributors' => 'συντελεστές', + 'pages' => 'σελίδες', + 'settings' => 'ρυθμίσεις', + 'theme' => 'θέμα', + 'about' => 'σχετικά', + 'add' => 'προσθήκη', + 'new' => 'νέο', + 'edit' => 'επεξεργασία', + 'persons' => 'άτομα', + 'publish' => 'δημοσίευση', + 'publish-edit' => 'επεξεργασία δημοσίευσης', + 'publish-date-edit' => 'επεξεργασία ημερομηνίας δημοσίευσης', + 'unpublish' => 'αναίρεση δημοσίευσης', + 'delete' => 'διαγραφή', + 'remove' => 'αφαίρεση', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'χρήστες', + 'my-account' => 'ο λογαριασμός μου', + 'change-password' => 'αλλαγή κωδικού πρόσβασης', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'πλατφόρμες', + 'social' => 'κοινωνικά δίκτυα', + 'funding' => 'χρηματοδότηση', + 'monetization-other' => 'other monetization', + 'analytics' => 'αναλυτικά στοιχεία', + 'locations' => 'τοποθεσίες', + 'webpages' => 'ιστοσελίδες', + 'unique-listeners' => 'μοναδικοί ακροατές', + 'players' => 'παίκτες', + 'listening-time' => 'χρόνος ακρόασης', + 'time-periods' => 'χρονικές περίοδοι', + 'soundbites' => 'ήχοι', + 'video-clips' => 'βίντεο κλιπς', + 'embed' => 'ενσωματώσιμος αναπαραγωγέας', + 'notifications' => 'ειδοποιήσεις', + 'suspend' => 'αναστολή', +]; diff --git a/modules/Admin/Language/el/Charts.php b/modules/Admin/Language/el/Charts.php new file mode 100644 index 00000000..247a77e7 --- /dev/null +++ b/modules/Admin/Language/el/Charts.php @@ -0,0 +1,41 @@ + 'Λήψεις επεισοδίων ανά υπηρεσία (για την προηγούμενη εβδομάδα)', + 'by_player_weekly' => 'Οι λήψεις επεισοδίων (για την προηγούμενη εβδομάδα)', + 'by_player_yearly' => 'Οι λήψεις επεισοδίων (για τo προηγούμενο έτος)', + 'by_device_weekly' => 'Λήψεις επεισοδίων ανά συσκευή (για την προηγούμενη εβδομάδα)', + 'by_os_weekly' => 'Οι λήψεις επεισοδίων ανά λειτουργικό σύστημα (για την προηγούμενη εβδομάδα)', + 'podcast_by_region' => 'Λήψεις επεισοδίων ανά περιοχή (για την προηγούμενη εβδομάδα)', + 'unique_daily_listeners' => 'Καθημερινά μοναδικοί ακροατές', + 'unique_monthly_listeners' => 'Μηνιαίοι μοναδικοί ακροατές', + 'by_browser' => 'Χρήση ιστοσελίδων από το πρόγραμμα περιήγησης (για την προηγούμενη εβδομάδα)', + 'podcast_by_day' => 'Ημερήσιες λήψεις του επισοδίου', + 'podcast_by_month' => 'Μηνιαίες λήψεις επεισοδίων', + 'episode_by_day' => 'Ημερήσιες λήψεις επισοδείου (πρώτες 60 ημέρες)', + 'episode_by_month' => 'Μηνιαίες λήψεις επεισοδίων', + 'episodes_by_day' => + '5 τελευταίες λήψεις επεισοδίων (κατά τις πρώτες 60 ημέρες τους)', + 'by_country_weekly' => 'Λήψεις επεισοδίων ανά χώρα (για την προηγούμενη εβδομάδα)', + 'by_country_yearly' => 'Λήψεις επεισοδίων ανά χώρα (για το προηγούμενο έτος)', + 'by_domain_weekly' => 'Επισκέψεις ιστοσελίδας ανά πηγή (για την προηγούμενη εβδομάδα)', + 'by_domain_yearly' => 'Επισκέψεις ιστοσελίδας ανά πηγή (για το προηγούμενο έτος)', + 'by_entry_page' => 'Επισκέψεις ιστοσελίδων ανά σελίδα προορισμού (για την προηγούμενη εβδομάδα)', + 'podcast_bots' => 'Bots (Crawlers)', + 'daily_listening_time' => 'Ημερήσιος αθροιστικός χρόνος ακρόασης', + 'monthly_listening_time' => 'Μηνιαίος αθροιστικός χρόνος ακρόασης', + 'by_weekday' => 'Την ημέρα της εβδομάδας (για τις τελευταίες 60 ημέρες)', + 'by_hour' => 'Κατά την ώρα της ημέρας (για τις τελευταίες 60 ημέρες)', + 'podcast_by_bandwidth' => 'Ημερήσιο χρησιμοποιούμενο bandwidth (σε MB)', + 'total_storage_by_month' => 'Μηνιαία αποθήκευση (σε MB)', + 'total_bandwidth_by_month' => 'Μηνιαίο χρησιμοποιούμενο εύρος ζώνης (σε MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/el/Common.php b/modules/Admin/Language/el/Common.php new file mode 100644 index 00000000..7bf5bbec --- /dev/null +++ b/modules/Admin/Language/el/Common.php @@ -0,0 +1,52 @@ + 'Ναι', + 'no' => 'Όχι', + 'cancel' => 'Ακύρωση', + 'optional' => 'Προαιρετικό', + 'more' => 'Περισσότερα', + 'no_data' => 'Δεν βρέθηκαν δεδομένα!', + 'close' => 'Κλείσιμο', + 'edit' => 'Επεξεργασία', + 'copy' => 'Αντιγραφή', + 'copied' => 'Αντιγράφηκε!', + 'home' => 'Αρχική σελίδα', + 'explicit' => 'Άσεμνο περιεχόμενο', + 'powered_by' => 'Με την υποστήριξη του {castopod}', + 'actions' => 'Ενέργειες', + 'pageInfo' => 'Σελίδα {currentPage} από {pageCount}', + 'go_back' => 'Επιστροφή', + 'forms' => [ + 'editor' => [ + 'write' => 'Εγγραφή', + 'preview' => 'Προεπισκόπηση', + 'help' => 'Με την υποστήριξη του markdown επεξεραστή', + ], + 'multiSelect' => [ + 'selectText' => 'Πατήστε για να επιλέξετε', + 'loadingText' => 'Φόρτωση σε εξέλιξη…', + 'noResultsText' => 'Δε βρέθηκαν αποτελέσματα', + 'noChoicesText' => 'Δεν υπάρχουν επιλογές επιλογής από', + 'maxItemText' => 'Αδυναμία προσθήκης περισσότερων αντικειμένων', + ], + 'upload_file' => 'Μεταφορτώστε ένα αρχείο', + 'remote_url' => 'Απομακρυσμένη διεύθυνση URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Αναπαραγωγή', + 'playing' => 'Αναπαράγεται', + ], + 'size_limit' => 'Όριο μεγέθους: {0}.', + 'choose_interact' => 'Επιλέξτε τον τρόπο αλληλεπίδρασης', + 'view' => 'Προβολή', +]; diff --git a/modules/Admin/Language/el/Countries.php b/modules/Admin/Language/el/Countries.php new file mode 100644 index 00000000..76a33e3e --- /dev/null +++ b/modules/Admin/Language/el/Countries.php @@ -0,0 +1,264 @@ + 'Ανδόρα', + 'AE' => 'Ηνωμένα Αραβικά Εμιράτα', + 'AF' => 'Αφγανιστάν', + 'AG' => 'Αντίγκουα και Μπαρπούντα', + 'AI' => 'Ανγκουΐλα', + 'AL' => 'Αλβανία', + 'AM' => 'Αρμενία', + 'AO' => 'Αγκόλα', + 'AQ' => 'Ανταρκτική', + 'AR' => 'Αργεντινή', + 'AS' => 'Αμερικανικές Σαμόα', + 'AT' => 'Αυστρία', + 'AU' => 'Αυστραλία', + 'AW' => 'Αρούμπα', + 'AX' => 'Νήσοι Άαλαντ', + 'AZ' => 'Αζερμπαϊτζάν', + 'BA' => 'Βοσνία Ερζεγοβίνη', + 'BB' => 'Μπαρμπάντος', + 'BD' => 'Μπανγκλαντές', + 'BE' => 'Βέλγιο', + 'BF' => 'Μπουρκίνα Φάσο', + 'BG' => 'Βουλγαρία', + 'BH' => 'Μπαχρέιν', + 'BI' => 'Μπουρουντί', + 'BJ' => 'Μπενίν', + 'BL' => 'Άγιος Βαρθολομαίος', + 'BM' => 'Βερμούδες', + 'BN' => 'Μπρουνέι', + 'BO' => 'Πολυεθνικό Κράτος της Βολιβίας', + 'BQ' => 'Μπονέρ, Άγιος Ευστάθιος και Σάμπα', + 'BR' => 'Βραζιλία', + 'BS' => 'Μπαχάμες', + 'BT' => 'Μπουτάν', + 'BV' => 'Νήσος Μπουβέ', + 'BW' => 'Μποτσουάνα', + 'BY' => 'Λευκορωσία', + 'BZ' => 'Μπελίζ', + 'CA' => 'Καναδάς', + 'CC' => 'Νησιά Κόκος (Κήλινγκ)', + 'CD' => 'Λαϊκή Δημοκρατία του Κονγκό', + 'CF' => 'Δημοκρατία Κεντρικής Αφρικής', + 'CG' => 'Κονγκό', + 'CH' => 'Ελβετία', + 'CI' => "Ακτή του Ελεφαντοστού", + 'CK' => 'Νήσοι Κουκ', + 'CL' => 'Χιλή', + 'CM' => 'Καμερούν', + 'CN' => 'Κίνα', + 'CO' => 'Κολομβία', + 'CR' => 'Κόστα Ρίκα', + 'CU' => 'Κούβα', + 'CV' => 'Πράσινο Ακρωτήριο', + 'CW' => 'Κουρασάο', + 'CX' => 'Νήσος Χριστουγέννων', + 'CY' => 'Κύπρος', + 'CZ' => 'Δημοκρατία της Τσεχίας', + 'DE' => 'Γερμανία', + 'DJ' => 'Τζιμπουτί', + 'DK' => 'Δανία', + 'DM' => 'Ντομίνικα', + 'DO' => 'Δομινικανή Δημοκρατία', + 'DZ' => 'Αλγερία', + 'EC' => 'Εκουαδόρ', + 'EE' => 'Εσθονία', + 'EG' => 'Αίγυπτος', + 'EH' => 'Δυτική Σαχάρα', + 'ER' => 'Ερυθραία', + 'ES' => 'Ισπανία', + 'ET' => 'Αιθιοπία', + 'FI' => 'Φινλανδία', + 'FJ' => 'Φίτζι', + 'FK' => 'Νήσοι Φώκλαντ (Μαλβίνας)', + 'FM' => 'Ομοσπονδιακές Πολιτείες της Μικρονησίας', + 'FO' => 'Νήσοι Φερόες', + 'FR' => 'Γαλλία', + 'GA' => 'Γκαμπόν', + 'GB' => 'Ηνωμένο Βασίλειο', + 'GD' => 'Γρενάδα', + 'GE' => 'Γεωργία', + 'GF' => 'Γαλλική Γουϊάνα', + 'GG' => 'Γκέρνσεϊ', + 'GH' => 'Γκάνα', + 'GI' => 'Γιβραλτάρ', + 'GL' => 'Γροιλανδία', + 'GM' => 'Γκάμπια', + 'GN' => 'Γουϊνέα', + 'GP' => 'Γουαδελούπη', + 'GQ' => 'Ισημερινή Γουινέα', + 'GR' => 'Ελλάδα', + 'GS' => 'Νήσοι Νότια Γεωργία και Νότιες Σάντουιτς', + 'GT' => 'Γουατεμάλα', + 'GU' => 'Γκουάμ', + 'GW' => 'Γουινέα-Μπισάου', + 'GY' => 'Γουϊάνα', + 'HK' => 'Χονγκ Κονγκ', + 'HM' => 'Νήσοι Χερντ και Μακντόναλντ', + 'HN' => 'Ονδούρα', + 'HR' => 'Κροατία', + 'HT' => 'Αϊτή', + 'HU' => 'Ουγγαρία', + 'ID' => 'Ινδονησία', + 'IE' => 'Ιρλανδία', + 'IL' => 'Ισραήλ', + 'IM' => 'Νήσος του Μαν', + 'IN' => 'Ινδία', + 'IO' => 'Βρετανικό Έδαφος του Ινδικού Ωκεανού', + 'IQ' => 'Ιράκ', + 'IR' => 'Ιράν', + 'IS' => 'Ισλανδία', + 'IT' => 'Ιταλία', + 'JE' => 'Τζέρσεϊ', + 'JM' => 'Τζαμάικα', + 'JO' => 'Ιορδανία', + 'JP' => 'Ιαπωνία', + 'KE' => 'Κένυα', + 'KG' => 'Κιργιστάν', + 'KH' => 'Καμπότζη', + 'KI' => 'Κιριμπάτι', + 'KM' => 'Κομόρες', + 'KN' => 'Σεν Κιτς και Νέβις', + 'KP' => "Λαϊκή Δημοκρατία της Κορέας", + 'KR' => 'Δημοκρατία της Κορέας', + 'KW' => 'Κουβέιτ', + 'KY' => 'Νησιά Καϋμάν', + 'KZ' => 'Καζακστάν', + 'LA' => "Λαϊκή Δημοκρατία του Λάος", + 'LB' => 'Λίβανος', + 'LC' => 'Αγία Λουκία', + 'LI' => 'Λίχτενσταϊν', + 'LK' => 'Σρι Λάνκα', + 'LR' => 'Λιβερία', + 'LS' => 'Λεσόθο', + 'LT' => 'Λιθουανία', + 'LU' => 'Λουξεμβούργο', + 'LV' => 'Λετονία', + 'LY' => 'Λιβύη', + 'MA' => 'Μαρόκο', + 'MC' => 'Μονακό', + 'MD' => 'Δημοκρατία της Μολδαβίας', + 'ME' => 'Μαυροβούνιο', + 'MF' => 'Άγιος Μαρτίνος (Γαλλικό τμήμα)', + 'MG' => 'Μαδαγασκάρη', + 'MH' => 'Νήσοι Μάρσαλ', + 'MK' => 'Βόρεια Μακεδονία, Πρώην Γιουγκοσλαβική Δημοκρατία της Μακεδονίας', + 'ML' => 'Μάλι', + 'MM' => 'Μιανμάρ', + 'MN' => 'Μογγολία', + 'MO' => 'Μακάο', + 'MP' => 'Βόρειες Μαριάνες Νήσοι', + 'MQ' => 'Μαρτινίκα', + 'MR' => 'Μαυριτανία', + 'MS' => 'Μοντσερράτ', + 'MT' => 'Μάλτα', + 'MU' => 'Μαυρίκιος', + 'MV' => 'Μαλδίβες', + 'MW' => 'Μαλάουι', + 'MX' => 'Μεξικό', + 'MY' => 'Μαλαισία', + 'MZ' => 'Μοζαμβίκη', + 'N/A' => 'Δεν ισχύει (τοπική IP…)', + 'NA' => 'Ναμίμπια', + 'NC' => 'Νέα Καληδονία', + 'NE' => 'Νιγηρία', + 'NF' => 'Νήσος Νόρφολκ', + 'NG' => 'Νιγηρία', + 'NI' => 'Νικαράγουα', + 'NL' => 'Ολλανδία', + 'NO' => 'Νορβηγία', + 'NP' => 'Νεπάλ', + 'NR' => 'Ναουρού', + 'NU' => 'Νιούε', + 'NZ' => 'Νέα Ζηλανδία', + 'OM' => 'Ομάν', + 'PA' => 'Παναμάς', + 'PE' => 'Περού', + 'PF' => 'Γαλλική Πολυνησία', + 'PG' => 'Παπούα Νέα Γουινέα', + 'PH' => 'Φιλιππίνες', + 'PK' => 'Πακιστάν', + 'PL' => 'Πολωνία', + 'PM' => 'Άγιος Πέτρος (Σεν Πιέρ) και Μικελόν', + 'PN' => 'Νήσοι Πίτκαιρν', + 'PR' => 'Πουέρτο Ρίκο', + 'PS' => 'Κράτος της Παλαιστίνης', + 'PT' => 'Πορτογαλία', + 'PW' => 'Παλάου', + 'PY' => 'Παραγουάη', + 'QA' => 'Κατάρ', + 'RE' => 'Ρεϋνιόν', + 'RO' => 'Ρουμανία', + 'RS' => 'Σερβία', + 'RU' => 'Ρωσική Ομοσπονδία', + 'RW' => 'Ρουάντα', + 'SA' => 'Σαουδική Αραβία', + 'SB' => 'Νήσοι Σολομώντος', + 'SC' => 'Σεϋχέλλες', + 'SD' => 'Σουδάν', + 'SE' => 'Σουηδία', + 'SG' => 'Σιγκαπούρη', + 'SH' => 'Αγία Ελένη, της Αναλήψεως και Τριστάν ντα Κούνια', + 'SI' => 'Σλοβενία', + 'SJ' => 'Σβάλμπαρντ και Γιαν Μαγιέν', + 'SK' => 'Σλοβακία', + 'SL' => 'Σιέρα Λεόνε', + 'SM' => 'Σαν Μαρίνο', + 'SN' => 'Σενεγάλη', + 'SO' => 'Σομαλία', + 'SR' => 'Σουρινάμ', + 'SS' => 'Νότιο Σουδάν', + 'ST' => 'Άγιος Θωμάς και Πρίγκιπας (Σάο Τομέ και Πρίντσιπε)', + 'SV' => 'Ελ Σαλβαδόρ', + 'SX' => 'Άγιος Μαρτίνος (Γερμανικό τμήμα)', + 'SY' => 'Αραβική Δημοκρατία της Συρίας', + 'SZ' => 'Σουαζιλάνδη', + 'TC' => 'Νήσοι Τερκς και Κάικος', + 'TD' => 'Τσαντ', + 'TF' => 'Γαλλικές περιοχές του νοτίου ημισφαιρίου', + 'TG' => 'Τόγκο', + 'TH' => 'Ταϊλάνδη', + 'TJ' => 'Τατζικιστάν', + 'TK' => 'Τοκελάου', + 'TL' => 'Τιμόρ-Λέστε', + 'TM' => 'Τουρκμενιστάν', + 'TN' => 'Τυνησία', + 'TO' => 'Τόνγκα', + 'TR' => 'Τουρκία', + 'TT' => 'Τρινιντάντ και Τομπάγκο', + 'TV' => 'Τουβαλού', + 'TW' => 'Ταϊβάν, Επαρχία της Κίνας', + 'TZ' => 'Ενωμένη Δημοκρατία της Τανζανίας', + 'UA' => 'Ουκρανία', + 'UG' => 'Ουγκάντα', + 'UM' => 'Απομακρυσμένες Νησίδες των Ηνωμένων Πολιτειών', + 'US' => 'Ηνωμένες Πολιτείες', + 'UY' => 'Ουρουγουάη', + 'UZ' => 'Ουζμπεκιστάν', + 'VA' => 'Αγία Έδρα (κράτος της πόλης του Βατικανού)', + 'VC' => 'Άγιος Βικέντιος και Γρεναδίνες', + 'VE' => 'Μπολιβαριανής Δημοκρατίας της Βενεζουέλας', + 'VG' => 'Βρετανικές Παρθένοι Νήσοι', + 'VI' => 'Παρθένοι Νήσοι, Η.Π.Α.', + 'VN' => 'Βιετνάμ', + 'VU' => 'Βανουάτου', + 'WF' => 'Ουώλλις και Φουτούνα', + 'WS' => 'Σαμόα', + 'YE' => 'Υεμένη', + 'YT' => 'Μαγιότ', + 'ZA' => 'Νότια Αφρική', + 'ZM' => 'Ζάμπια', + 'ZW' => 'Ζιμπάμπουε', +]; diff --git a/modules/Admin/Language/el/Dashboard.php b/modules/Admin/Language/el/Dashboard.php new file mode 100644 index 00000000..b780ea20 --- /dev/null +++ b/modules/Admin/Language/el/Dashboard.php @@ -0,0 +1,28 @@ + 'Πίνακας ελέγχου διαχειριστή', + 'welcome_message' => 'Καλώς ήρθατε στην περιοχή διαχείρισης!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Δεν υπάρχει δημοσιευμένο podcast', + 'last_published' => 'Τελευταία δημοσίευση στις {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Επεισόδια', + 'not_found' => 'Κανένα δημοσιευμένο επεισόδιο', + 'last_published' => 'Τελευταία δημοσίευση στις {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Αποθηκευτικός χώρος', + 'subtitle' => '{totalUploaded} από {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/el/Episode.php b/modules/Admin/Language/el/Episode.php new file mode 100644 index 00000000..cf72d9e7 --- /dev/null +++ b/modules/Admin/Language/el/Episode.php @@ -0,0 +1,225 @@ + 'Σεζόν {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Επεισόδιο {episodeNumber}', + 'number_abbr' => 'Επ. {episodeNumber}', + 'season_episode' => 'Σεζόν {seasonNumber} επεισόδιο {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}:E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# σχόλιο} + other {# σχόλεια} + }', + 'all_podcast_episodes' => 'Όλα τα επεισόδια του podcast', + 'back_to_podcast' => 'Μετάβαση πίσω στο podcast', + 'edit' => 'Επεξεργασία', + 'preview' => 'Preview', + 'publish' => 'Δημοσίευση', + 'publish_edit' => 'Επεξεργασία δημοσίευσης', + 'publish_date_edit' => 'Επεξεργασία ημερομηνίας δημοσίευσης', + 'unpublish' => 'Αναίρεση δημοσίευσης', + 'publish_error' => 'Το επεισόδιο έχει ήδη δημοσιευθεί.', + 'publish_edit_error' => 'Το επεισόδιο έχει ήδη δημοσιευθεί.', + 'publish_cancel_error' => 'Το επεισόδιο έχει ήδη δημοσιευθεί.', + 'publish_date_edit_error' => 'Το επεισόδιο δεν έχει δημοσιευθεί ακόμα, δεν μπορείτε να επεξεργαστείτε την ημερομηνία έκδοσής του.', + 'publish_date_edit_future_error' => 'Η ημερομηνία δημοσίευσης του επεισοδίου μπορεί να οριστεί μόνο σε μια προηγούμενη ημερομηνία! Αν θέλετε να την προγραμματίσετε εκ νέου, αποδημοσιεύστε την πρώτα.', + 'publish_date_edit_success' => 'Η ημερομηνία δημοσίευσης του επεισοδίου έχει ενημερωθεί με επιτυχία!', + 'unpublish_error' => 'Το επεισόδιο δεν έχει δημοσιευθεί.', + 'delete' => 'Διαγραφή', + 'go_to_page' => 'Μετάβαση στη σελίδα', + 'create' => 'Προσθήκη επεισοδίου', + 'publication_status' => [ + 'published' => 'Δημοσιευμένο', + 'with_podcast' => 'Δημοσιευμένο', + 'scheduled' => 'Προγραμματισμένο', + 'not_published' => 'Δεν έχει δημοσιευτεί', + ], + 'with_podcast_hint' => 'Να δημοσιευτεί ταυτόχρονα με το podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Αναζήτηση ενός επεισοδίου', + 'clear' => 'Καθαρισμός αναζήτησης', + 'submit' => 'Αναζήτηση', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# επισόδειο} + other {# επισόδεια} + }', + 'episode' => 'Επεισόδιο', + 'visibility' => 'Ορατότητα', + 'downloads' => 'Downloads', + 'comments' => 'Σχόλια', + 'actions' => 'Ενέργειες', + ], + 'messages' => [ + 'createSuccess' => 'Το επεισόδιο δημιουργήθηκε με επιτυχία!', + 'editSuccess' => 'Το επεισόδιο ενημερώθηκε με επιτυχία!', + 'publishSuccess' => '{publication_status, select, + published {Το επεισόδιο δημοσιεύτηκε με επιτυχία!} + scheduled {Η έκδοση για το επεισόδιο έχει προγραμματιστεί επιτυχώς!} + with_podcast {Αυτό το επεισόδιο θα δημοσιευθεί ταυτόχρονα με το podcast.} + other {Αυτό το επεισόδιο δεν έχει δημοσιευθεί.} + }', + 'publishCancelSuccess' => 'Η δημοσίευση του επεισοδίου ακυρώθηκε επιτυχώς!', + 'unpublishBeforeDeleteTip' => 'Πρέπει να καταργήσετε τη δημοσίευση του επεισοδίου πριν τη διαγραφή.', + 'scheduleDateError' => 'Η ημερομηνία πρέπει να οριστεί!', + 'deletePublishedEpisodeError' => 'Πρέπει να καταργήσετε τη δημοσίευση του επεισοδίου πριν τη διαγραφή.', + 'deleteSuccess' => 'Το επεισόδιο διαγράφτηκε με επιτυχία!', + 'deleteError' => 'Αποτυχία διαγραφής επεισοδίου {type, select, + transcript {transcript} + chapters {κεφάλαια} + image {καλύπτουν} + audio {ήχος} + other {πολυμέσα} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Ένα επεισόδιο με το επιλεγμένο slug υπάρχει ήδη.', + ], + 'form' => [ + 'file_size_error' => + 'Το μέγεθος του αρχείου σας είναι πολύ μεγάλο! Το μέγιστο μέγεθος είναι {0}. Αυξήστε τις τιμές `memory_limit`, `upload_max_filesize` και `post_max_size` στο αρχείο ρυθμίσεων php και έπειτα επανεκκινήστε τον διακομιστή web για να ανεβάσετε το αρχείο σας.', + 'audio_file' => 'Αρχείο ήχου', + 'audio_file_hint' => 'Επιλέξτε ένα αρχείο ήχου .mp3 ή .m4a.', + 'info_section_title' => 'Πληροφορίες επεισοδίου', + 'cover' => 'Εξώφυλλο επισοδίου', + 'cover_hint' => + 'Εάν δεν ορίσετε ένα εξώφυλλο, το εξώφυλλο του podcast θα χρησιμοποιηθεί αντ \'αυτού.', + 'cover_size_hint' => 'Το εξώφυλλο πρέπει να είναι τουλάχιστον 1400px πλάτος και ύψος.', + 'title' => 'Τίτλος', + 'title_hint' => + 'Θα πρέπει να υπάρχει ένα σαφές και συνοπτικό όνομα επεισοδίου. Μην καθορίσετε εδώ το επεισόδιο ή τους αριθμούς της σεζόν.', + 'permalink' => 'Μόνιμος σύνδεσμος', + 'season_number' => 'Σεζόν', + 'episode_number' => 'Επεισόδιο', + 'type' => [ + 'label' => 'Είδος', + 'full' => 'Πλήρης', + 'full_hint' => 'Πλήρες περιεχόμενο (το επεισόδιο)', + 'trailer' => 'Τρέιλερ', + 'trailer_hint' => 'Σύντομο, προωθητικό περιεχόμενο που αντιπροσωπεύει μια προεπισκόπηση της τρέχουσας εμφάνισης', + 'bonus' => 'Μπόνους', + 'bonus_hint' => 'Επιπλέον περιεχόμενο για την παράσταση (για παράδειγμα, πίσω από τις σκηνές πληροφορίες ή συνεντεύξεις με τη cast) ή δια-διαφημιστικό περιεχόμενο για μια άλλη παράσταση', + ], + 'premium_title' => 'Premium', + 'premium' => 'Το επεισόδιο πρέπει να είναι προσβάσιμο μόνο σε συνδρομητές premium', + 'parental_advisory' => [ + 'label' => 'Γονικός σύμβουλος', + 'hint' => 'Μήπως το επεισόδιο περιέχει ακατάλληλο περιεχόμενο;', + 'undefined' => 'απροσδιόριστο', + 'clean' => 'Καθαρισμός', + 'explicit' => 'Άσεμνο περιεχόμενο', + ], + 'show_notes_section_title' => 'Εμφάνιση σημειώσεων', + 'show_notes_section_subtitle' => + 'Μέχρι 4000 χαρακτήρες, να είναι σαφείς και συνοπτικές. Η εμφάνιση σημειώσεων βοηθάει πιθανούς ακροατές στην εύρεση του επεισοδίου.', + 'description' => 'Περιγραφή', + 'description_footer' => 'Υποσέλιδο περιγραφής', + 'description_footer_hint' => + 'Αυτό το κείμενο προστίθεται στο τέλος του κάθε επεισοδίου, είναι ένα καλό μέρος για να εισάγετε κοινωνικές συνδέσεις για παράδειγμα.', + 'additional_files_section_title' => 'Επιπρόσθετα αρχεία', + 'additional_files_section_subtitle' => + 'Αυτά τα αρχεία μπορούν να χρησιμοποιηθούν από άλλες πλατφόρμες για την παροχή καλύτερης εμπειρίας στο κοινό σας. Δείτε το {podcastNamespaceLink} για περισσότερες πληροφορίες.', + 'location_section_title' => 'Τοποθεσία', + 'location_section_subtitle' => 'Σε ποιο μέρος είναι αυτό το επεισόδιο;', + 'location_name' => 'Όνομα τοποθεσίας ή διεύθυνση', + 'location_name_hint' => 'Αυτή μπορεί να είναι μια πραγματική ή φανταστική τοποθεσία', + 'transcript' => 'Απομαγνητοφώνηση (υπότιτλοι / κλειστοί υπότιτλοι)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Λήψη απομαγνητοφώνησης', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Απομακρυσμένη διεύθυνση url για απομαγνητοφώνηση', + 'transcript_file_delete' => 'Διαγραφή αρχείου απομαγνητοφώνησης', + 'chapters' => 'Κεφάλαια', + 'chapters_hint' => 'Το αρχείο πρέπει να είναι σε μορφή JSON.', + 'chapters_download' => 'Κατεβάστε τα κεφάλαια', + 'chapters_file' => 'Αρχεία κεφαλαίων', + 'chapters_remote_url' => 'Απομακρυσμένη διεύθυνση url για αρχεία κεφαλαίων', + 'chapters_file_delete' => 'Διαγραφή αρχείου κεφαλαίων', + 'advanced_section_title' => 'Προηγμένες Παράμετροι', + 'advanced_section_subtitle' => + 'Αν χρειάζεστε ετικέτες RSS που δεν χειρίζεται το Castopod, ορίστε τις εδώ.', + 'custom_rss' => 'Προσαρμοσμένες ετικέτες RSS για το επεισόδιο', + 'custom_rss_hint' => 'Αυτό θα ενεθεί εντός της ετικέτας "item".', + 'block' => 'Το επεισόδιο πρέπει να είναι κρυμμένο από όλες τις πλατφόρμες', + 'block_hint' => + 'H κατάσταση εμφάνιση ή απόκρυψη επισοδείου: Η εναλλαγή αποτρέπει την εμφάνιση του επεισοδίου στο Apple Podcast Google Podcasts, και σε οποιεσδήποτε εφαρμογή τρίτων που τραβούν τις εμφανίσεις από αυτούς τους καταλόγους. (Μη εγγυημένη)', + 'submit_create' => 'Δημιουργία επεισοδίου', + 'submit_edit' => 'Αποθήκευση επεισοδίου', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Πίσω στον Πίνακα Ελέγχου', + 'post' => 'Η ανακοίνωσή σας', + 'post_hint' => + "Γράψτε ένα μήνυμα για να ανακοινώσετε τη δημοσίευση του επεισοδίου σας. Το μήνυμα θα μεταδοθεί σε όλους τους οπαδούς σας στο fediverse και θα εμφανίζεται στην αρχική σελίδα του podcast σας.", + 'message_placeholder' => 'Γράψτε το μήνυμά σας…', + 'publication_date' => 'Ημερομηνία δημοσίευσης', + 'publication_method' => [ + 'now' => 'Τώρα', + 'schedule' => 'Προγραμματισμός', + 'with_podcast' => 'Δημοσίευση παράλληλα με podcast', + ], + 'scheduled_publication_date' => 'Ημερομηνία προγραμματισμένης δημοσίευσης', + 'scheduled_publication_date_clear' => 'Εκκαθάριση ημερομηνίας δημοσίευσης', + 'scheduled_publication_date_hint' => + 'Μπορείτε να προγραμματίσετε την έκδοση επεισοδίων ορίζοντας μια μελλοντική ημερομηνία δημοσίευσης. Αυτό το πεδίο πρέπει να μορφοποιηθεί ως ΕΕΕ-ΜΜ-ΗΗ HH:mm', + 'submit' => 'Δημοσίευση', + 'submit_edit' => 'Επεξεργασία δημοσίευσης', + 'cancel_publication' => 'Ακύρωση δημοσίευσης', + 'message_warning' => 'Δεν γράψατε μήνυμα για την ανακοίνωσή σας!', + 'message_warning_hint' => 'Έχοντας ένα μήνυμα αυξάνει την κοινωνική δέσμευση, με αποτέλεσμα μια καλύτερη προβολή για το επεισόδιο σας.', + 'message_warning_submit' => 'Δημοσίευση ούτως ή άλλως', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Ημερομηνία νέας δημοσίευσης', + 'new_publication_date_hint' => 'Πρέπει να οριστεί σε μια προηγούμενη ημερομηνία.', + 'submit' => 'Επεξεργασία ημερομηνίας δημοσίευσης', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Η κατάργηση της δημοσίευσης του επεισοδίου θα διαγράψει όλα τα σχόλια και τις δημοσιεύσεις που σχετίζονται με αυτό και θα τα αφαιρέσει από τη ροή RSS του podcast.", + 'understand' => 'Καταλαβαίνω, θέλω να αποδημοσιεύσει το επεισόδιο', + 'submit' => 'Αναίρεση δημοσίευσης', + ], + 'delete_form' => [ + 'disclaimer' => + "Διαγράφοντας το επεισόδιο θα διαγράψετε όλα τα αρχεία πολυμέσων, τα σχόλια, τα βίντεο κλιπ και τα ηχητικά δεδομένα που σχετίζονται με αυτό.", + 'understand' => 'Καταλαβαίνω, θέλω να διαγράψω το επεισόδιο', + 'submit' => 'Διαγραφή', + ], + 'embed' => [ + 'title' => 'Ενσωματώσιμος αναπαραγωγέας', + 'label' => + 'Επιλέξτε ένα χρώμα θέματος, αντιγράψτε τον ενσωματωμένο παίκτη στο πρόχειρο και στη συνέχεια επικολλήστε το στην ιστοσελίδα σας.', + 'clipboard_iframe' => 'Αντιγραφή ενσωματωμένου αναπαραγωγέα στο πρόχειρο', + 'clipboard_url' => 'Αντιγραφή διεύθυνσης στο πρόχειρο', + 'dark' => 'Σκοτεινό', + 'dark-transparent' => 'Σκούρο διαφανές', + 'light' => 'Ανοιχτόχρωμο', + 'light-transparent' => 'Ανοιχτό διαφανές', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/el/EpisodeNavigation.php b/modules/Admin/Language/el/EpisodeNavigation.php new file mode 100644 index 00000000..c2a9ccdd --- /dev/null +++ b/modules/Admin/Language/el/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Προβολή σελίδας επεισοδίου', + 'dashboard' => 'Πίνακας εργαλείων επεισοδίου', + 'episode-view' => 'Αρχική σελίδα', + 'episode-edit' => 'Επεξεργασία επεισοδίου', + 'episode-persons-manage' => 'Διαχείριση ατόμων', + 'embed-add' => 'Ενσωματώσιμος αναπαραγωγέας', + 'clips' => 'Αποσπάσματα', + 'video-clips-list' => 'Βίντεο κλιπς', + 'video-clips-create' => 'Νέο βίντεο κλιπ', + 'soundbites-list' => 'Ήχοι', + 'soundbites-create' => 'Νέο soundbite', +]; diff --git a/modules/Admin/Language/el/Fediverse.php b/modules/Admin/Language/el/Fediverse.php new file mode 100644 index 00000000..b75a73f1 --- /dev/null +++ b/modules/Admin/Language/el/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Δεν βρέθηκε ο λογαριασμός!', + 'blockActorSuccess' => '{0} έχει αποκλειστεί!', + 'unblockActorSuccess' => 'Ο ηθοποιός έχει ξεμπλοκαριστεί!', + 'blockDomainSuccess' => '{domain} έχει αποκλειστεί!', + 'unblockDomainSuccess' => '{domain} έχει ξεμπλοκαριστεί!', + ], + 'blocked_actors' => 'Αποκλεισμένοι λογαριασμοί', + 'blocked_domains' => 'Αποκλεισμένοι τομείς', + 'block_lists_form' => [ + 'handle' => 'Χειρισμός λογαριασμού', + 'handle_hint' => 'Εισαγωγή λογαριασμού @username@domain.', + 'domain' => 'Όνομα τομέα', + 'submit' => 'Αποκλεισμός!', + ], + 'list' => [ + 'actor' => 'Λογαριασμός', + 'domain' => 'Όνομα τομέα', + 'unblock' => 'Ξεμπλοκάρισμα', + ], +]; diff --git a/modules/Admin/Language/el/Home.php b/modules/Admin/Language/el/Home.php new file mode 100644 index 00000000..c160f26d --- /dev/null +++ b/modules/Admin/Language/el/Home.php @@ -0,0 +1,14 @@ + 'Όλα τα podcasts', + 'no_podcast' => 'Δεν βρέθηκαν podcast', +]; diff --git a/modules/Admin/Language/el/Install.php b/modules/Admin/Language/el/Install.php new file mode 100644 index 00000000..80c07026 --- /dev/null +++ b/modules/Admin/Language/el/Install.php @@ -0,0 +1,61 @@ + 'Χειροκίνητη ρύθμιση', + 'manual_config_subtitle' => + 'Δημιουργήστε ένα αρχείο `.env` με τις ρυθμίσεις σας και ανανεώστε τη σελίδα για να συνεχίσετε την εγκατάσταση.', + 'form' => [ + 'instance_config' => 'Ρύθμιση παραμέτρων εμφάνισης', + 'hostname' => 'Όνομα κεντρικού υπολογιστή', + 'media_base_url' => 'Διεύθυνση URL πολυμέσων', + 'media_base_url_hint' => + 'Εάν χρησιμοποιείτε μια υπηρεσία CDN και/ ή μια εξωτερική υπηρεσία ανάλυσης, μπορείτε να την ρυθμίσετε εδώ.', + 'admin_gateway' => 'Πύλη διαχειριστή', + 'admin_gateway_hint' => + 'Η διαδρομή πρόσβασης στην περιοχή διαχειριστή (π.χ. https://example.com/cp-admin). Έχει οριστεί από προεπιλογή ως cp-admin, σας συνιστούμε να την αλλάξετε για λόγους ασφαλείας.', + 'auth_gateway' => 'Πύλη ταυτοποίησης', + 'auth_gateway_hint' => + 'Η διαδρομή πρόσβασης στην περιοχή διαχειριστή (π.χ. https://example.com/cp-auth). Έχει οριστεί από προεπιλογή ως cp-admin, σας συνιστούμε να την αλλάξετε για λόγους ασφαλείας.', + 'database_config' => 'Ρυθμίσεις βάσης δεδομένων', + 'database_config_hint' => + 'Το Castopod πρέπει να συνδεθεί στη βάση δεδομένων MySQL (ή MariaDB). Αν δεν έχετε αυτές τις απαιτούμενες πληροφορίες, παρακαλούμε επικοινωνήστε με το διαχειριστή του διακομιστή σας.', + 'db_hostname' => 'Όνομα κεντρικού υπολογιστή βάσης δεδομένων', + 'db_name' => 'Όνομα βάσης δεδομένων', + 'db_username' => 'Όνομα Χρήστη Βάσης Δεδομένων', + 'db_password' => 'Κωδικός πρόσβασης βάσης δεδομένων', + 'db_prefix' => 'Πρόθεμα βάσης δεδομένων', + 'db_prefix_hint' => + "Το πρόθεμα των ονομασιών πινάκων Castopod αφήστε σαν να μην ξέρετε τι σημαίνει.", + 'cache_config' => 'Διαμόρφωση cache', + 'cache_config_hint' => + 'Επιλέξτε τον προτιμώμενο χειριστή προσωρινής μνήμης. Αφήστε την προεπιλεγμένη τιμή αν δεν έχετε ιδέα τι σημαίνει.', + 'cache_handler' => 'Ρυθμιστής cache', + 'cacheHandlerOptions' => [ + 'file' => 'Αρχείο', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Επόμενο', + 'submit' => 'Ολοκλήρωση εγκατάστασης', + 'create_superadmin' => 'Δημιουργήστε το λογαριασμό υπερδιαχειριστή', + 'email' => 'Email', + 'username' => 'Όνομα Χρήστη', + 'password' => 'Κωδικόs πρόσβασης', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ο λογαριασμός υπερδιαχειριστή έχει δημιουργηθεί με επιτυχία. Συνδεθείτε για να ξεκινήσετε το podcasting!', + 'databaseConnectError' => + 'Το Castopod δεν μπόρεσε να συνδεθεί στη βάση δεδομένων σας. Επεξεργαστείτε τη διαμόρφωση της βάσης δεδομένων σας και προσπαθήστε ξανά.', + 'writeError' => + "Δεν ήταν δυνατή η δημιουργία/εγγραφή του αρχείου `.env`. Πρέπει να το δημιουργήσετε χειροκίνητα ακολουθώντας το πρότυπο αρχείου `.env.example` που περιγράφεται στο Castopod.", + ], +]; diff --git a/modules/Admin/Language/el/Navigation.php b/modules/Admin/Language/el/Navigation.php new file mode 100644 index 00000000..8d766a63 --- /dev/null +++ b/modules/Admin/Language/el/Navigation.php @@ -0,0 +1,44 @@ + 'Εναλλαγή πλαϊνής μπάρας', + 'go_to_website' => 'Μεταβείτε στον ιστότοπο', + 'go_to_admin' => 'Μεταβείτε στον πίνακα διαχείρισης', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Πίνακας εργαλείων', + 'admin' => 'Αρχική σελίδα', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Όλα τα podcasts', + 'podcast-create' => 'Νέο podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Πρόσωπα', + 'person-list' => 'Όλα τα άτομα', + 'person-create' => 'Νέο άτομο', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Αποκλεισμένοι λογαριασμοί', + 'fediverse-blocked-domains' => 'Αποκλεισμένοι τομείς', + 'users' => 'Χρήστες', + 'user-list' => 'Όλοι οι χρήστες', + 'user-create' => 'Νέος χρήστης', + 'pages' => 'Σελίδες', + 'page-list' => 'Όλες οι σελίδες', + 'page-create' => 'Νέα σελίδα', + 'settings' => 'Ρυθμίσεις', + 'settings-general' => 'Γενικά', + 'settings-theme' => 'Θέμα', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'Ο λογαριασμός μου', + 'change-password' => 'Αλλαγή κωδικού πρόσβασης', + 'logout' => 'Αποσυνδέση', + ], +]; diff --git a/modules/Admin/Language/el/Notifications.php b/modules/Admin/Language/el/Notifications.php new file mode 100644 index 00000000..3e87ddba --- /dev/null +++ b/modules/Admin/Language/el/Notifications.php @@ -0,0 +1,19 @@ + 'Ειδοποιήσεις', + 'reply' => '{actor_username} απάντησε στο post σας', + 'favourite' => '{actor_username} έβαλε αγαπημένη τη δημοσίευσή σας', + 'reblog' => '{actor_username} κοινοποίησε τη δημοσίευσή σας', + 'follow' => '{actor_username} ξεκίνησε να σας ακολουθεί', + 'no_notifications' => 'Καμία ειδοποίηση', + 'mark_all_as_read' => 'Σήμανση όλων ως αναγνωσμένα', +]; diff --git a/modules/Admin/Language/el/Page.php b/modules/Admin/Language/el/Page.php new file mode 100644 index 00000000..00358402 --- /dev/null +++ b/modules/Admin/Language/el/Page.php @@ -0,0 +1,30 @@ + 'Επιστροφή στην αρχική σελίδα', + 'page' => 'Σελίδα', + 'all_pages' => 'Όλες οι σελίδες', + 'create' => 'Νέα σελίδα', + 'go_to_page' => 'Μετάβαση στη σελίδα', + 'edit' => 'Επεξεργασία σελίδας', + 'delete' => 'Διαγραφή σελίδας', + 'form' => [ + 'title' => 'Τίτλος', + 'permalink' => 'Μόνιμος σύνδεσμος', + 'content' => 'Περιεχόμενο', + 'submit_create' => 'Δημιουργία σελίδας', + 'submit_edit' => 'Αποθήκευση', + ], + 'messages' => [ + 'createSuccess' => 'Η σελίδα “{pageTitle}” δημιουργήθηκε με επιτυχία!', + 'editSuccess' => 'Η σελίδα ενημερώθηκε επιτυχώς!', + ], +]; diff --git a/modules/Admin/Language/el/Pager.php b/modules/Admin/Language/el/Pager.php new file mode 100644 index 00000000..31c0354d --- /dev/null +++ b/modules/Admin/Language/el/Pager.php @@ -0,0 +1,21 @@ + 'Πλοήγηση στις σελίδες', + 'first' => 'Πρώτη', + 'previous' => 'Προηγούμενη', + 'next' => 'Επόμενη', + 'last' => 'Τελευταία', + 'older' => 'Παλιότερα', + 'newer' => 'Νεότερη', + 'invalidTemplate' => '{0} δεν είναι έγκυρο πρότυπο Pager.', + 'invalidPaginationGroup' => '{0} δεν είναι μια έγκυρη ομάδα σελιδοποίησης.', +]; diff --git a/modules/Admin/Language/el/Person.php b/modules/Admin/Language/el/Person.php new file mode 100644 index 00000000..4235a337 --- /dev/null +++ b/modules/Admin/Language/el/Person.php @@ -0,0 +1,65 @@ + 'Πρόσωπα', + 'all_persons' => 'Όλα τα πρόσωπα', + 'no_person' => 'Δεν βρέθηκε κανείς!', + 'create' => 'Δημιουργήστε ένα πρόσωπο', + 'view' => 'Προβολή προσώπου', + 'edit' => 'Επεξεργασία προσώπου', + 'delete' => 'Διαγραφή ατόμου', + 'messages' => [ + 'createSuccess' => 'Το άτομο δημιουργήθηκε με επιτυχία!', + 'editSuccess' => 'Το άτομο ενημερώθηκε με επιτυχία!', + 'deleteSuccess' => 'Το άτομο έχει αφαιρεθεί!', + ], + 'form' => [ + 'avatar' => 'Είδωλο', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Ονοματεπώνυμο', + 'full_name_hint' => 'Αυτό είναι το πλήρες όνομα ή το ψευδώνυμο του ατόμου.', + 'unique_name' => 'Μοναδικό όνομα', + 'unique_name_hint' => 'Χρησιμοποιείται για διευθύνσεις URL', + 'information_url' => 'Url Πληροφοριών', + 'information_url_hint' => + 'Url σε μια σχετική πηγή πληροφοριών σχετικά με το άτομο, όπως μια αρχική σελίδα ή πλατφόρμα προφίλ τρίτων.', + 'submit_create' => 'Δημιουργία προσώπου', + 'submit_edit' => 'Αποθήκευση ατόμου', + ], + 'podcast_form' => [ + 'title' => 'Διαχείριση προσώπων', + 'add_section_title' => 'Προσθέστε άτομα σε αυτό το podcast', + 'add_section_subtitle' => 'Μπορείτε να επιλέξετε πολλά άτομα και ρόλους.', + 'persons' => 'Πρόσωπα', + 'persons_hint' => + 'Μπορείτε να επιλέξετε ένα ή περισσότερα άτομα με τους ίδιους ρόλους. Πρέπει πρώτα να δημιουργήσετε τα πρόσωπα.', + 'roles' => 'Ρόλοι', + 'roles_hint' => + 'Μπορείτε να επιλέξετε κανένα, έναν ή περισσότερους ρόλους για ένα άτομο.', + 'submit_add' => 'Προσθήκη ατόμου(ων)', + 'remove' => 'Διαγραφή', + ], + 'episode_form' => [ + 'title' => 'Διαχείριση προσώπων', + 'add_section_title' => 'Προσθήκη ατόμων σε αυτό το επεισόδιο', + 'add_section_subtitle' => 'Μπορείτε να επιλέξετε πολλά άτομα και ρόλους.', + 'persons' => 'Πρόσωπα', + 'persons_hint' => + 'Μπορείτε να επιλέξετε ένα ή περισσότερα άτομα με τους ίδιους ρόλους. Πρέπει πρώτα να δημιουργήσετε τα πρόσωπα.', + 'roles' => 'Ρόλοι', + 'roles_hint' => + 'Μπορείτε να επιλέξετε κανένα, έναν ή περισσότερους ρόλους για ένα άτομο.', + 'submit_add' => 'Προσθήκη ατόμου(ων)', + 'remove' => 'Διαγραφή', + ], + 'credits' => 'Συντελεστές', +]; diff --git a/modules/Admin/Language/el/Platforms.php b/modules/Admin/Language/el/Platforms.php new file mode 100644 index 00000000..2c5a10ec --- /dev/null +++ b/modules/Admin/Language/el/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Μεταβείτε στην ιστοσελίδα {platformName}', + 'register' => 'Register', + 'submit_url' => 'Υποβάλετε το podcast σας στην πλατφόρμα {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Εμφάνιση στην αρχική σελίδα του podcast;', + 'on_embed' => 'Εμφάνιση σε ενσωματωμένο player;', + 'remove' => 'Κατάργηση {platformName}', + 'submit' => 'Αποθήκευση', + 'messages' => [ + 'updateSuccess' => 'Οι σύνδεσμοι της πλατφόρμας ενημερώθηκαν επιτυχώς!', + 'removeLinkSuccess' => 'Ο σύνδεσμος πλατφόρμας έχει αφαιρεθεί.', + 'removeLinkError' => + 'Δεν ήταν δυνατή η αφαίρεση του συνδέσμου της πλατφόρμας. Δοκιμάστε ξανά.', + ], + 'description' => [ + 'podcasting' => 'Το αναγνωριστικό podcast σε αυτή την πλατφόρμα', + 'social' => 'Το αναγνωριστικό λογαριασμού podcast σε αυτήν την πλατφόρμα', + 'funding' => 'Κλήση σε μήνυμα δράσης', + ], +]; diff --git a/modules/Admin/Language/el/Podcast.php b/modules/Admin/Language/el/Podcast.php new file mode 100644 index 00000000..d24fa87c --- /dev/null +++ b/modules/Admin/Language/el/Podcast.php @@ -0,0 +1,330 @@ + 'Όλα τα podcasts', + 'no_podcast' => 'Δεν βρέθηκαν podcast!', + 'create' => 'Δημιουργία podcast', + 'import' => 'Εισαγωγή ενός podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Νέο Επεισόδιο', + 'view' => 'Προβολή podcast', + 'edit' => 'Επεξεργασία podcast', + 'publish' => 'Δημοσίευση podcast', + 'publish_edit' => 'Επεξεργασία δημοσίευσης', + 'delete' => 'Διαγραφή podcast', + 'see_episodes' => 'Δείτε επεισόδια', + 'see_contributors' => 'Βλέπε συντελεστές', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Μετάβαση στη σελίδα', + 'latest_episodes' => 'Τελευταία επεισόδια', + 'see_all_episodes' => 'Δείτε όλα τα επεισόδια', + 'draft' => 'Πρόχειρο', + 'messages' => [ + 'createSuccess' => 'Το επεισόδιο δημιουργήθηκε με επιτυχία!', + 'editSuccess' => 'Το Podcast ενημερώθηκε με επιτυχία!', + 'importSuccess' => 'Το Podcast εισήχθη με επιτυχία!', + 'deleteSuccess' => 'Το Podcast @{podcast_handle} διαγράφηκε επιτυχώς!', + 'deletePodcastMediaError' => 'Αποτυχία διαγραφής podcast {type, select, + cover {εξώφυλλο} + banner {banner} + other {πολυμέσα} + }.', + 'deleteEpisodeMediaError' => 'Αποτυχία διαγραφής του podcast επεισοδίου {episode_slug} {type, select, + transcript {transcript} + chapters {κεφάλαια} + image {κάλυμμα} + audio {ήχος} + other {πολυμέσα} + }.', + 'deletePodcastMediaFolderError' => 'Αποτυχία διαγραφής του φακέλου μέσων podcast {folder_path}. Μπορείτε να τον αφαιρέσετε χειροκίνητα από το δίσκο σας.', + 'podcastFeedUpdateSuccess' => 'Επιτυχημένη ενημέρωση: {number_of_new_episodes, plural, + one {# επεισόδιο ήταν} + other {# επεισόδια ήταν} + } προστέθηκαν στο podcast!', + 'podcastFeedUpToDate' => 'Το Podcast είναι ήδη ενημερωμένο.', + 'publishError' => 'Αυτό το podcast είτε έχει ήδη δημοσιευθεί είτε έχει προγραμματιστεί για δημοσίευση.', + 'publishEditError' => 'Αυτό το podcast δεν έχει προγραμματιστεί για δημοσίευση.', + 'publishCancelSuccess' => 'Η δημοσίευση του επεισοδίου ακυρώθηκε επιτυχώς!', + 'scheduleDateError' => 'Η ημερομηνία πρέπει να οριστεί!', + ], + 'form' => [ + 'identity_section_title' => 'Αναγνωριστικό Podcast', + 'identity_section_subtitle' => 'Αυτά τα πεδία σας επιτρέπουν να ξεχωρίσει το podcast σας.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Εξώφυλο podcast', + 'cover_size_hint' => 'Το εξώφυλλο πρέπει να είναι τουλάχιστον 1400px πλάτος και ύψος.', + 'banner' => 'Banner podcast', + 'banner_size_hint' => 'Το Banner πρέπει να έχει αναλογία 3:1 και να είναι τουλάχιστον 1500px πλάτος.', + 'banner_delete' => 'Διαγραφή του podcast banner', + 'title' => 'Τίτλος', + 'handle' => 'Handle', + 'handle_hint' => + 'Χρησιμοποιείται για τον προσδιορισμό του podcast. Τα κεφαλαία, τα πεζά, οι αριθμοί και οι κάτω παύλες γίνονται αποδεκτές.', + 'type' => [ + 'label' => 'Είδος', + 'episodic' => 'Episodic', + 'episodic_hint' => 'Εάν τα επεισόδια προορίζονται να καταναλωθούν χωρίς καμία συγκεκριμένη σειρά.', + 'serial' => 'Σειριακός Αριθμός', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Περιγραφή', + 'classification_section_title' => 'Χαρακτηρισμός', + 'classification_section_subtitle' => + 'Αυτά τα πεδία θα επηρεάσουν το κοινό και τον ανταγωνισμό σας.', + 'language' => 'Γλώσσα', + 'category' => 'Κατηγορία', + 'category_placeholder' => 'Επιλέξτε μια κατηγορία…', + 'other_categories' => 'Άλλες κατηγορίες', + 'parental_advisory' => [ + 'label' => 'Γονικός σύμβουλος', + 'hint' => 'Μήπως το επεισόδιο περιέχει ακατάλληλο περιεχόμενο;', + 'undefined' => 'απροσδιόριστο', + 'clean' => 'Καθαρισμός', + 'explicit' => 'Άσεμνο περιεχόμενο', + ], + 'author_section_title' => 'Συντάκτης', + 'author_section_subtitle' => 'Ποιος διαχειρίζεται το podcast;', + 'owner_name' => 'Όνομα κατόχου', + 'owner_name_hint' => + 'Μόνο για διοικητική χρήση. Ορατό στη δημόσια τροφοδοσία RSS.', + 'owner_email' => 'Email ιδιοκτήτη', + 'owner_email_hint' => + 'Θα χρησιμοποιηθεί από τις περισσότερες πλατφόρμες για να επαληθεύσει την ιδιοκτησία του podcast. Ορατό στη δημόσια τροφοδοσία RSS.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Εκδότης', + 'publisher_hint' => + 'Η ομάδα που είναι υπεύθυνη για τη δημιουργία της παράστασης. Συχνά αναφέρεται στη μητρική εταιρεία ή στο δίκτυο ενός podcast. Αυτό το πεδίο μερικές φορές χαρακτηρίζεται ως \'Συγγραφέας\'.', + 'copyright' => 'Πνευματικά δικαιώματα', + 'location_section_title' => 'Τοποθεσία', + 'location_section_subtitle' => 'Σε ποιο μέρος είναι αυτό το επεισόδιο;', + 'location_name' => 'Όνομα τοποθεσίας ή διεύθυνση', + 'location_name_hint' => 'Αυτό μπορεί να είναι ένα πραγματικό μέρος ή φανταστικό', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Κερδίστε χρήματα χάρη στο κοινό σας.', + 'premium' => 'Premium', + 'premium_by_default' => 'Τα επεισόδια πρέπει να ορίζονται ως premium από προεπιλογή', + 'premium_by_default_hint' => 'Τα επεισόδια Podcast θα επισημανθούν ως premium από προεπιλογή. Μπορείτε ακόμα να επιλέξετε να ορίσετε κάποια επεισόδια, trailers ή μπόνους ως δημόσια.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Δείκτης πληρωμής για Monetization Web', + 'payment_pointer_hint' => + 'Αυτό είναι το πού θα λάβετε χρήματα χάρη στην Monetization Web', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Καριέρες', + 'entrepreneurship' => 'Επιχειρηματικότητα', + 'investing' => 'Επενδύσεις', + 'management' => 'Διαχείριση', + 'marketing' => 'Μάρκετινγκ', + 'non_profit' => 'Μη κερδοσκοπικού χαρακτήρα', + 'comedy_interviews' => 'Συνεντεύξεις Κωμωδίας', + 'improv' => 'Βελτίωση', + 'stand_up' => 'Stand-Up', + 'courses' => 'Σεμινάρια', + 'how_to' => 'How To', + 'language_learning' => 'Εκμάθηση γλωσσών', + 'self_improvement' => 'Αυτοβελτίωση', + 'comedy_fiction' => 'Φαντασία Κωμωδίας', + 'drama' => 'Δράμα', + 'science_fiction' => 'Επιστημονικής φαντασίας', + 'alternative_health' => 'Εναλλακτική Υγεία', + 'fitness' => 'Γυμναστική', + 'medicine' => 'Ιατρική', + 'mental_health' => 'Ψυχική Υγεία', + 'nutrition' => 'Διατροφή', + 'sexuality' => 'Σεξουαλικότητα', + 'education_for_kids' => 'Εκπαίδευση για παιδιά', + 'parenting' => 'Γονείς', + 'pets_and_animals' => 'Κατοικίδια & Ζώα', + 'stories_for_kids' => 'Ιστορίες για παιδιά', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Αυτοκίνητα', + 'aviation' => 'Αεροπορία', + 'crafts' => 'Χειροτεχνίες', + 'games' => 'Παιχνίδια', + 'hobbies' => 'Χόμπι', + 'home_and_garden' => 'Σπίτι & Κήπος', + 'video_games' => 'Βιντεοπαιχνίδια', + 'music_commentary' => 'Σχολιασμός Μουσικής', + 'music_history' => 'Ιστορία Μουσικής', + 'music_interviews' => 'Συνεντεύξεις Μουσικής', + 'business_news' => 'Επιχειρηματικά Νέα', + 'daily_news' => 'Καθημερινές Ειδήσεις', + 'entertainment_news' => 'Ειδήσεις ψυχαγωγίας', + 'news_commentary' => 'News Commentary', + 'politics' => 'Πολιτική', + 'sports_news' => 'Αθλητικά νέα', + 'tech_news' => 'Ειδήσεις Τεχνολογίας', + 'buddhism' => 'Βουδισμός', + 'christianity' => 'Χριστιανισμός', + 'hinduism' => 'Hinduism', + 'islam' => 'Ισλαμισμός', + 'judaism' => 'Ιουδαϊσμός', + 'religion' => 'Θρησκεία', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Έχοντας ένα μήνυμα αυξάνει την κοινωνική δέσμευση, με αποτέλεσμα μια καλύτερη ορατότητα για το podcast σας.', + 'message_warning_submit' => 'Δημοσίευση ούτως ή άλλως', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'λειτουργία πρόχειρου', + 'not_published' => 'Αυτό το podcast δεν έχει ακόμη δημοσιευθεί.', + 'scheduled' => 'Αυτό το podcast έχει προγραμματιστεί για δημοσίευση στις {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Διαγράφοντας το podcast θα διαγράψει όλα τα επεισόδια, τα αρχεία πολυμέσων, τις δημοσιεύσεις και τα αναλυτικά στοιχεία που σχετίζονται με αυτό. Αυτή η ενέργεια είναι μη αναστρέψιμη, δεν θα είστε σε θέση να τις ανακτήσετε αργότερα.", + 'understand' => 'Καταλαβαίνω, θέλω το podcast να διαγραφεί οριστικά', + 'submit' => 'Διαγραφή', + ], + 'by' => 'Από {publisher}', + 'season' => 'Σεζόν {seasonNumber}', + 'list_of_episodes_year' => '{year} επεισόδια ({episodeCount})', + 'list_of_episodes_season' => + 'Σεζόν {seasonNumber} επεισόδεια ({episodeCount})', + 'no_episode' => 'Δεν βρέθηκε επεισόδιο!', + 'follow' => 'Ακολουθήστε', + 'followers' => '{numberOfFollowers, plural, + one {# ακόλουθος} + other {# ακόλουθοι} + }', + 'posts' => '{numberOfPosts, plural, + one {# δημοσίευση} + other {# δημοσιεύσεις} + }', + 'activity' => 'Δραστηριότητα', + 'episodes' => 'Επεισόδια', + 'sponsor' => 'Χορηγός', + 'funding_links' => 'Σύνδεσμοι χρηματοδότησης για το {podcastTitle}', + 'find_on' => 'Βρείτε το {podcastTitle} στο', + 'listen_on' => 'Ακούστε το', +]; diff --git a/modules/Admin/Language/el/PodcastNavigation.php b/modules/Admin/Language/el/PodcastNavigation.php new file mode 100644 index 00000000..d5310a9a --- /dev/null +++ b/modules/Admin/Language/el/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Μετάβαση στη σελίδα podcast', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Πίνακας ελέγχου Podcast', + 'podcast-view' => 'Αρχική σελίδα', + 'podcast-edit' => 'Επεξεργασία podcast', + 'podcast-persons-manage' => 'Διαχείριση ατόμων', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Επεισόδια', + 'episode-list' => 'Όλα τα επεισόδια', + 'episode-create' => 'Νέο Επεισόδιο', + 'analytics' => 'Στατιστικά', + 'podcast-analytics' => 'Επισκόπηση κοινού', + 'podcast-analytics-webpages' => 'Επίσκεψη ιστοσελίδων', + 'podcast-analytics-locations' => 'Τοποθεσίες', + 'podcast-analytics-unique-listeners' => 'Μοναδικοί ακροατές', + 'podcast-analytics-players' => 'Αναπαραγωγές', + 'podcast-analytics-listening-time' => 'Χρόνος ακρόασης', + 'podcast-analytics-time-periods' => 'Χρονικές περίοδοι', + 'monetization' => 'Monetization', + 'subscription-list' => 'Όλες οι συνδρομές', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Συντελεστές', + 'contributor-list' => 'Όλοι οι συντελεστές', + 'contributor-add' => 'Προσθήκη συντελεστή', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Κοινωνικά δίκτυα', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/el/Settings.php b/modules/Admin/Language/el/Settings.php new file mode 100644 index 00000000..d4ff241b --- /dev/null +++ b/modules/Admin/Language/el/Settings.php @@ -0,0 +1,58 @@ + 'Γενικές ρυθμίσεις', + 'instance' => [ + 'title' => 'Διακομιστής', + 'site_icon' => 'Εικονίδιο ιστοσελίδας', + 'site_icon_delete' => 'Διαγραφή εικονιδίου ιστότοπου', + 'site_icon_hint' => 'Τα εικονίδια της ιστοσελίδας είναι αυτά που βλέπετε στις καρτέλες του προγράμματος περιήγησης, στη γραμμή σελιδοδεικτών, και όταν προσθέτετε μια ιστοσελίδα ως συντόμευση σε κινητές συσκευές.', + 'site_icon_helper' => 'Το εικονίδιο πρέπει να είναι τετράγωνο και τουλάχιστον 512px πλάτος και ψηλό.', + 'site_name' => 'Όνομα ιστοτόπου', + 'site_description' => 'Περιγραφή ιστοτόπου', + 'submit' => 'Αποθήκευση', + 'editSuccess' => 'Ο Διακομιστής έχει ενημερωθεί με επιτυχία!', + 'deleteIconSuccess' => 'Το εικονίδιο της ιστοσελίδας έχει καταργηθεί με επιτυχία!', + ], + 'images' => [ + 'title' => 'Εικόνες', + 'subtitle' => 'Εδώ μπορείτε να επαναδημιουργήσετε όλες τις εικόνες με βάση τα πρωτότυπα που φορτώθηκαν. Για να χρησιμοποιηθεί αν βρείτε κάποιες εικόνες που λείπουν. Αυτή η εργασία μπορεί να διαρκέσει λίγο.', + 'regenerate' => 'Αναδημιουργία εικόνων', + 'regenerationSuccess' => 'Όλες οι εικόνες έχουν δημιουργηθεί επιτυχώς!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Επαναφορά μετρήσεων', + 'reset_counts_helper' => 'Αυτή η επιλογή θα επαναϋπολογίσει και θα επαναφέρει όλους τους αριθμούς δεδομένων (αριθμός των ακολούθων, αναρτήσεις, σχόλια, …).', + 'rewrite_media' => 'Επανεγγραφή μεταδεδομένων πολυμέσων', + 'rewrite_media_helper' => 'Αυτή η επιλογή θα διαγράψει όλα τα περιττά αρχεία πολυμέσων και θα τα αναπαράγει (εικόνες, αρχεία ήχου, μεταγραφές, κεφάλαια, …)', + 'rename_episodes_files' => 'Μετονομασία αρχείων ήχου επεισοδίου', + 'rename_episodes_files_hint' => 'Αυτή η επιλογή θα μετονομάσει όλα τα αρχεία ήχου επεισόδια σε μια τυχαία συμβολοσειρά χαρακτήρων. Χρησιμοποιήστε αυτό αν διαρρεύσει ένας από τους ιδιωτικούς συνδέσμους επεισοδίων σας, καθώς αυτό θα τον αποκρύψει αποτελεσματικά.', + 'clear_cache' => 'Εκκαθάριση συνολικού cache', + 'clear_cache_helper' => 'Αυτή η επιλογή θα εκκαθαρίσει αρχεία cache redis ή εγγράψιμο/cache.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Θέμα', + 'accent_section_title' => 'Χρώμα έμφασης', + 'accent_section_subtitle' => 'Επιλέξτε το χρώμα για να καθορίσετε την εμφάνιση και την αίσθηση όλων των δημόσιων σελίδων.', + 'pine' => 'Πεύκο', + 'crimson' => 'Βυσσινί', + 'amber' => 'Κεχριμπάρι', + 'lake' => 'Λίμνη', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Όνυξ', + 'submit' => 'Αποθήκευση', + 'setInstanceThemeSuccess' => 'Το θέμα έχει ενημερωθεί με επιτυχία!', + ], +]; diff --git a/modules/Admin/Language/el/Soundbite.php b/modules/Admin/Language/el/Soundbite.php new file mode 100644 index 00000000..122bdb1d --- /dev/null +++ b/modules/Admin/Language/el/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Ήχοι', + 'soundbite' => 'Ήχος', + ], + 'messages' => [ + 'createSuccess' => 'Το Soundbite δημιουργήθηκε με επιτυχία!', + 'deleteSuccess' => 'Το Soundbite αφαιρέθηκε με επιτυχία!', + ], + 'form' => [ + 'title' => 'Νέο soundbite', + 'soundbite_title' => 'Τίτλος Soundbite', + 'start_time' => 'Έναρξη από', + 'duration' => 'Διάρκεια', + 'submit' => 'Δημιουργία soundbite', + ], + 'play' => 'Αναπαραγωγή soundbite', + 'stop' => 'Σταμάτημα soundbite', + 'create' => 'Νέο soundbite', + 'delete' => 'Διαγραφή soundbite', +]; diff --git a/modules/Admin/Language/el/Validation.php b/modules/Admin/Language/el/Validation.php new file mode 100644 index 00000000..2c5bcf7c --- /dev/null +++ b/modules/Admin/Language/el/Validation.php @@ -0,0 +1,17 @@ + + '{field} είτε δεν είναι μια εικόνα, είτε δεν είναι αρκετά ευρεία ή ψηλή.', + 'is_image_ratio' => + '{field} είτε δεν είναι εικόνα είτε όχι της σωστής αναλογίας.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/el/VideoClip.php b/modules/Admin/Language/el/VideoClip.php new file mode 100644 index 00000000..64388b13 --- /dev/null +++ b/modules/Admin/Language/el/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Βίντεο κλιπ', + 'status' => [ + 'label' => 'Κατάσταση', + 'queued' => 'στην ουρά', + 'queued_hint' => 'Το κλιπ περιμένει να υποβληθεί σε επεξεργασία.', + 'pending' => 'εκκρεμεί', + 'pending_hint' => 'Το κλιπ θα δημιουργηθεί σύντομα.', + 'running' => 'εκτελείται', + 'running_hint' => 'Το κλιπ δημιουργείται.', + 'failed' => 'απέτυχε', + 'failed_hint' => 'Το κλιπ δεν μπόρεσε να δημιουργηθεί: αποτυχία δέσμης ενεργειών.', + 'passed' => 'passed', + 'passed_hint' => 'Το κλιπ δημιουργήθηκε με επιτυχία!', + ], + 'clip' => 'Αποσπάσματα', + 'duration' => 'Διάρκεια εργασίας', + ], + 'title' => 'Βίντεο κλιπ: {videoClipLabel}', + 'download_clip' => 'Κατεβάστε το κλιπ', + 'create' => 'Νέο βίντεο κλιπ', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Διαγραφή κλιπ', + 'logs' => 'Αρχεία καταγραφής εργασίας', + 'messages' => [ + 'alreadyExistingError' => 'Το βίντεο κλιπ που προσπαθείτε να δημιουργήσετε υπάρχει ήδη!', + 'addToQueueSuccess' => 'Το βίντεο κλιπ έχει προστεθεί στην ουρά αναμονής, αναμένοντας να δημιουργηθεί!', + 'deleteSuccess' => 'Το βίντεο κλιπ αφαιρέθηκε με επιτυχία!', + ], + 'format' => [ + 'landscape' => 'Οριζόντια', + 'portrait' => 'Κατακόρυφα', + 'squared' => 'Τετράγωνα', + ], + 'form' => [ + 'title' => 'Νέο βίντεο κλιπ', + 'params_section_title' => 'Παράμετροι βίντεο κλιπ', + 'clip_title' => 'Τίτλος κλιπ', + 'format' => [ + 'label' => 'Επιλογή μορφής', + 'landscape_hint' => 'Με αναλογία 16:9, τα βίντεο τοπίου είναι υπέροχα για το PeerTube, το Youtube και το Vimeo.', + 'portrait_hint' => 'Με αναλογία 9:16, πορτρέτο βίντεο είναι μεγάλη για TikTok, shorts Youtube και ιστορίες Instagram.', + 'squared_hint' => 'Με αναλογία 1:1, τα τετράγωνα βίντεο είναι υπέροχα για Mastodon, Facebook, Twitter και LinkedIn.', + ], + 'theme' => 'Επιλογή θέματος', + 'start_time' => 'Έναρξη από', + 'duration' => 'Διάρκεια', + 'trim_start' => 'Περικοπή έναρξης', + 'trim_end' => 'Περικοπή τέλους', + 'submit' => 'Δημιουργία βίντεο κλιπ', + ], + 'requirements' => [ + 'title' => 'Λείπουν προαπαιτούμενα', + 'missing' => 'Έχετε απαιτήσεις που λείπουν. Σιγουρευτείτε ότι προσθέστε όλα τα απαιτούμενα στοιχεία για να μπορέσετε να δημιουργήσετε ένα βίντεο για αυτό το επεισόδιο!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Σχεδίαση Γραφικών (GD)', + 'freetype' => 'Βιβλιοθήκη Freetype για GD', + 'transcript' => 'Αρχείο απομαγνητοφώνησης (.srt)', + ], +]; diff --git a/modules/Admin/Language/en/AboutCastopod.php b/modules/Admin/Language/en/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/en/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/en/Breadcrumb.php b/modules/Admin/Language/en/Breadcrumb.php new file mode 100644 index 00000000..fedd6b19 --- /dev/null +++ b/modules/Admin/Language/en/Breadcrumb.php @@ -0,0 +1,58 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'plugins' => 'plugins', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/en/Charts.php b/modules/Admin/Language/en/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/en/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/en/Common.php b/modules/Admin/Language/en/Common.php new file mode 100644 index 00000000..4dff9dd4 --- /dev/null +++ b/modules/Admin/Language/en/Common.php @@ -0,0 +1,56 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'fieldArray' => [ + 'add' => 'Add', + 'remove' => 'Remove', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/en/Countries.php b/modules/Admin/Language/en/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/en/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/en/Dashboard.php b/modules/Admin/Language/en/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/en/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/en/Episode.php b/modules/Admin/Language/en/Episode.php new file mode 100644 index 00000000..f7eb1290 --- /dev/null +++ b/modules/Admin/Language/en/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_description' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_description' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_description' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/en/EpisodeNavigation.php b/modules/Admin/Language/en/EpisodeNavigation.php new file mode 100644 index 00000000..ef3cdec0 --- /dev/null +++ b/modules/Admin/Language/en/EpisodeNavigation.php @@ -0,0 +1,24 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', + 'plugins' => 'Plugins', +]; diff --git a/modules/Admin/Language/en/Fediverse.php b/modules/Admin/Language/en/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/en/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/en/Home.php b/modules/Admin/Language/en/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/en/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/en/Install.php b/modules/Admin/Language/en/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/en/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/en/Navigation.php b/modules/Admin/Language/en/Navigation.php new file mode 100644 index 00000000..fc7cfc30 --- /dev/null +++ b/modules/Admin/Language/en/Navigation.php @@ -0,0 +1,46 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'plugins' => 'Plugins', + 'plugins-installed' => 'Installed', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/en/Notifications.php b/modules/Admin/Language/en/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/en/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/en/Page.php b/modules/Admin/Language/en/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/en/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/en/Pager.php b/modules/Admin/Language/en/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/en/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/en/Person.php b/modules/Admin/Language/en/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/en/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/en/Platforms.php b/modules/Admin/Language/en/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/en/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/en/Podcast.php b/modules/Admin/Language/en/Podcast.php new file mode 100644 index 00000000..89fa9491 --- /dev/null +++ b/modules/Admin/Language/en/Podcast.php @@ -0,0 +1,332 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_description' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_description' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_description' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_description' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_description' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'redirect_to_new_feed' => 'Automatically redirect to new feed (301 redirect)', + 'redirect_to_new_feed_hint' => 'Check this when migrating your Castopod RSS feed to the new feed url set above. To ensure followers receive your most recent episodes from the new feed URL, maintain this redirect and the tag in your new feed for at least four weeks.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/en/PodcastNavigation.php b/modules/Admin/Language/en/PodcastNavigation.php new file mode 100644 index 00000000..a6b73e4a --- /dev/null +++ b/modules/Admin/Language/en/PodcastNavigation.php @@ -0,0 +1,43 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'plugins' => 'Plugins', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/en/Settings.php b/modules/Admin/Language/en/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/en/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/en/Soundbite.php b/modules/Admin/Language/en/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/en/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/en/Validation.php b/modules/Admin/Language/en/Validation.php new file mode 100644 index 00000000..4db0fe89 --- /dev/null +++ b/modules/Admin/Language/en/Validation.php @@ -0,0 +1,19 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', + 'is_boolean' => 'The {field} field must be a boolean (true or false).', + 'is_list' => 'The {field} field must be an array.', +]; diff --git a/modules/Admin/Language/en/VideoClip.php b/modules/Admin/Language/en/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/en/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/es/AboutCastopod.php b/modules/Admin/Language/es/AboutCastopod.php new file mode 100644 index 00000000..93d4142b --- /dev/null +++ b/modules/Admin/Language/es/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Acerca de Castopod', + 'host_name' => 'Nombre del host', + 'version' => 'Versión de Castopod', + 'php_version' => 'Versión de PHP', + 'os' => 'Sistema Operativo', + 'languages' => 'Idiomas', + 'update_database' => 'Actualizar base de datos', + 'messages' => [ + 'databaseUpdateSuccess' => 'La base de datos esta actualizada!', + ], +]; diff --git a/modules/Admin/Language/es/Breadcrumb.php b/modules/Admin/Language/es/Breadcrumb.php new file mode 100644 index 00000000..6ffb6387 --- /dev/null +++ b/modules/Admin/Language/es/Breadcrumb.php @@ -0,0 +1,57 @@ + 'ruta de navegación', + config('Admin') + ->gateway => 'Inicio', + 'podcasts' => 'podcasts', + 'episodes' => 'episodios', + 'subscriptions' => 'suscripciones', + 'contributors' => 'colaboradores', + 'pages' => 'páginas', + 'settings' => 'configuración', + 'theme' => 'tema', + 'about' => 'acerca de', + 'add' => 'añadir', + 'new' => 'nuevo', + 'edit' => 'editar', + 'persons' => 'personas', + 'publish' => 'publicar', + 'publish-edit' => 'editar publicación', + 'publish-date-edit' => 'editar fecha de publicación', + 'unpublish' => 'anular publicación', + 'delete' => 'borrar', + 'remove' => 'eliminar', + 'fediverse' => 'fediverso', + 'blocked-actors' => 'actores bloqueado', + 'blocked-domains' => 'dominios bloqueados', + 'users' => 'usuarios', + 'my-account' => 'mi cuenta', + 'change-password' => 'cambiar contraseña', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'plataformas', + 'social' => 'redes sociales', + 'funding' => 'financiación | fondos', + 'monetization-other' => 'other monetization', + 'analytics' => 'estadísticas', + 'locations' => 'ubicaciones', + 'webpages' => 'páginas web', + 'unique-listeners' => 'oyentes únicos', + 'players' => 'reproductores', + 'listening-time' => 'tiempo de escucha', + 'time-periods' => 'periodos de tiempo', + 'soundbites' => 'fragmentos de sonido', + 'video-clips' => 'clips de vídeo', + 'embed' => 'reproductor embebido', + 'notifications' => 'notificaciones', + 'suspend' => 'suspender', +]; diff --git a/modules/Admin/Language/es/Charts.php b/modules/Admin/Language/es/Charts.php new file mode 100644 index 00000000..7294231c --- /dev/null +++ b/modules/Admin/Language/es/Charts.php @@ -0,0 +1,41 @@ + 'Episodios descargados por servicio (para la semana pasada)', + 'by_player_weekly' => 'Episodios descargados por reproductor (para la semana pasada)', + 'by_player_yearly' => 'Episodios descargados por reproductor (para el año pasado)', + 'by_device_weekly' => 'Episodios descargados por dispositivo (para la semana pasada)', + 'by_os_weekly' => 'Episodios descargados por O.S. (para la semana pasada)', + 'podcast_by_region' => 'Episodios descargados por región (para la semana pasada)', + 'unique_daily_listeners' => 'Oyentes únicos diarios', + 'unique_monthly_listeners' => 'Oyentes únicos mensuales', + 'by_browser' => 'Uso de páginas Web por navegador (para la semana pasada)', + 'podcast_by_day' => 'Descargas diarias de episodio', + 'podcast_by_month' => 'Descargas mensuales del episodio', + 'episode_by_day' => 'Descargas diarias de episodio (primeros 60 días)', + 'episode_by_month' => 'Descargas mensuales del episodio', + 'episodes_by_day' => + 'Últimas 5 descargas de episodios (durante sus primeros 60 días)', + 'by_country_weekly' => 'Descargas del episodio por país (durante la semana pasada)', + 'by_country_yearly' => 'Episodios descargados por país (para la semana pasada)', + 'by_domain_weekly' => 'Páginas web vistas por origen (para la semana pasada)', + 'by_domain_yearly' => 'Páginas web vistas por origen (para la semana pasada)', + 'by_entry_page' => 'Páginas web visitas por página principal (para la semana pasada)', + 'podcast_bots' => 'Bots (rastreadores)', + 'daily_listening_time' => 'Tiempo de escucha diario acumulado', + 'monthly_listening_time' => 'Tiempo de escucha mensual acumulado', + 'by_weekday' => 'Por día de semana (para los últimos 60 días)', + 'by_hour' => 'Por hora del día (para los últimos 60 días)', + 'podcast_by_bandwidth' => 'Ancho de banda diario usado (en MB)', + 'total_storage_by_month' => 'Almacenamiento mensual (en MB)', + 'total_bandwidth_by_month' => 'Ancho de banda mensual usado (en MB)', + 'total_bandwidth_by_month_limit' => 'Limitado a {totalBandwidth} al mes', +]; diff --git a/modules/Admin/Language/es/Common.php b/modules/Admin/Language/es/Common.php new file mode 100644 index 00000000..ff3987cc --- /dev/null +++ b/modules/Admin/Language/es/Common.php @@ -0,0 +1,52 @@ + 'Si', + 'no' => 'No', + 'cancel' => 'Cancelar', + 'optional' => 'Opcional', + 'more' => 'Más', + 'no_data' => '¡No se encontraron datos!', + 'close' => 'Cerrar', + 'edit' => 'Editar', + 'copy' => 'Copiar', + 'copied' => '¡Copiado!', + 'home' => 'Inicio', + 'explicit' => 'Explícito', + 'powered_by' => 'Desarrollado por {castopod}', + 'actions' => 'Acciones', + 'pageInfo' => 'Página {currentPage} de {pageCount}', + 'go_back' => 'Volver atrás', + 'forms' => [ + 'editor' => [ + 'write' => 'Escribir', + 'preview' => 'Vista previa', + 'help' => 'Desarrollado por markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Pulse para seleccionar', + 'loadingText' => 'Cargando…', + 'noResultsText' => '¡No se encontraron resultados!', + 'noChoicesText' => 'No hay opciones de las que elegir', + 'maxItemText' => 'No puede añadir más elementos', + ], + 'upload_file' => 'Subir un archivo', + 'remote_url' => 'URL remoto', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Reproducir', + 'playing' => 'Reproduciendo', + ], + 'size_limit' => 'Límite de tamaño: {0}.', + 'choose_interact' => 'Elegir cómo interactuar', + 'view' => 'Ver', +]; diff --git a/modules/Admin/Language/es/Countries.php b/modules/Admin/Language/es/Countries.php new file mode 100644 index 00000000..3624e9c4 --- /dev/null +++ b/modules/Admin/Language/es/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emiratos Árabes Unidos', + 'AF' => 'Afganistán', + 'AG' => 'Antigua y Barbuda', + 'AI' => 'Anguila', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antártida', + 'AR' => 'Argentina', + 'AS' => 'Samoa Americana', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Islas Åland', + 'AZ' => 'Azerbaiyán', + 'BA' => 'Bosnia-Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Bélgica', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Baréin', + 'BI' => 'Burundi', + 'BJ' => 'Benín', + 'BL' => 'San Bartolomé', + 'BM' => 'Bermudas', + 'BN' => 'Brunéi Darussalam', + 'BO' => 'Estado Plurinacional de Bolivia', + 'BQ' => 'Bonaire, San Eustaquio y Saba', + 'BR' => 'Brasil', + 'BS' => 'Bahamas', + 'BT' => 'Bután', + 'BV' => 'Isla Bouvet', + 'BW' => 'Botswana', + 'BY' => 'Bielorrusia', + 'BZ' => 'Belice', + 'CA' => 'Canadá', + 'CC' => 'Islas Cocos (Keeling)', + 'CD' => 'República Democrática del Congo', + 'CF' => 'República Centroafricana', + 'CG' => 'Congo', + 'CH' => 'Suiza', + 'CI' => "Costa de Marfil", + 'CK' => 'Islas Cook', + 'CL' => 'Chile', + 'CM' => 'Camerún', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cabo Verde', + 'CW' => 'Curazao', + 'CX' => 'Isla de Navidad', + 'CY' => 'Chipre', + 'CZ' => 'República Checa', + 'DE' => 'Alemania', + 'DJ' => 'Djibouti', + 'DK' => 'Dinamarca', + 'DM' => 'Dominica', + 'DO' => 'República Dominicana', + 'DZ' => 'Argelia', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egipto', + 'EH' => 'Sáhara Occidental', + 'ER' => 'Eritrea', + 'ES' => 'España', + 'ET' => 'Etiopía', + 'FI' => 'Finlandia', + 'FJ' => 'Fiji', + 'FK' => 'Islas Malvinas (Falkland Islands)', + 'FM' => 'Estados Federales de Micronesia', + 'FO' => 'Islas Feroe', + 'FR' => 'Francia', + 'GA' => 'Gabón', + 'GB' => 'Reino Unido', + 'GD' => 'Granada', + 'GE' => 'Georgia', + 'GF' => 'Guayana Francesa', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenlandia', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadalupe', + 'GQ' => 'Guinea Ecuatorial', + 'GR' => 'Grecia', + 'GS' => 'Islas Georgias del Sur y Sandwich del Sur', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Islas Heard y McDonald', + 'HN' => 'Honduras', + 'HR' => 'Croacia', + 'HT' => 'Haití', + 'HU' => 'Hungría', + 'ID' => 'Indonesia', + 'IE' => 'Irlanda', + 'IL' => 'Israel', + 'IM' => 'Isla de Man', + 'IN' => 'India', + 'IO' => 'Territorio Británico Del Océano Índico', + 'IQ' => 'Iraq', + 'IR' => 'República Islámica de Irán', + 'IS' => 'Islandia', + 'IT' => 'Italia', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordania', + 'JP' => 'Japón', + 'KE' => 'Kenia', + 'KG' => 'Kirguistán', + 'KH' => 'Camboya', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'San Cristóbal y Nevis', + 'KP' => "Corea del Norte", + 'KR' => 'República de Corea', + 'KW' => 'Kuwait', + 'KY' => 'Islas Caimán', + 'KZ' => 'Kazajstán', + 'LA' => "República Democrática Popular de Laos", + 'LB' => 'Líbano', + 'LC' => 'Santa Lucía', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesoto', + 'LT' => 'Lituania', + 'LU' => 'Luxemburgo', + 'LV' => 'Letonia', + 'LY' => 'Libia', + 'MA' => 'Marruecos', + 'MC' => 'Mónaco', + 'MD' => 'República de Moldova', + 'ME' => 'Montenegro', + 'MF' => 'San Martín (parte francesa)', + 'MG' => 'Malgache', + 'MH' => 'Islas Marshall', + 'MK' => 'Ex República Yugoslava de Macedonia', + 'ML' => 'Malí', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Islas Marianas del Norte', + 'MQ' => 'Martinica', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauricio', + 'MV' => 'Maldivas', + 'MW' => 'Malawi', + 'MX' => 'México', + 'MY' => 'Malasia', + 'MZ' => 'Mozambique', + 'N/A' => 'No aplicable (IP local…)', + 'NA' => 'Austria', + 'NC' => 'Nueva Caledonia', + 'NE' => 'Niger', + 'NF' => 'Isla Norfolk', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Países Bajos', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nueva Zelanda', + 'OM' => 'Omán', + 'PA' => 'Panamá', + 'PE' => 'Perú', + 'PF' => 'Polinesia Francesa', + 'PG' => 'Papúa Nueva Guinea', + 'PH' => 'Filipinas', + 'PK' => 'Pakistán', + 'PL' => 'Polonia', + 'PM' => 'San Pierre y Miquelón', + 'PN' => 'Islas Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Estado de Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palaos', + 'PY' => 'Paraguay', + 'QA' => 'Catar', + 'RE' => 'Reunión', + 'RO' => 'Rumanía', + 'RS' => 'Serbia', + 'RU' => 'Federación Rusa', + 'RW' => 'Ruanda', + 'SA' => 'Arabia Saudita', + 'SB' => 'Islas Salomón', + 'SC' => 'Seychelles', + 'SD' => 'Sudán', + 'SE' => 'Suecia', + 'SG' => 'Singapur', + 'SH' => 'Santa Elena, Ascensión y Tristán de Acuña', + 'SI' => 'Eslovenia', + 'SJ' => 'Svalbard y Jan Mayen', + 'SK' => 'Eslovaquia', + 'SL' => 'Sierra Leona', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Surinam', + 'SS' => 'Sudán del Sur', + 'ST' => 'Santo Tomé y Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'San Martín (Países Bajos)', + 'SY' => 'República Árabe Siria', + 'SZ' => 'Suiza', + 'TC' => 'Islas Turcas y Caicos', + 'TD' => 'Chad', + 'TF' => 'Territorios Australes Franceses', + 'TG' => 'Togo', + 'TH' => 'Tailandia', + 'TJ' => 'Tayikistán', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistán', + 'TN' => 'Túnez', + 'TO' => 'Tonga', + 'TR' => 'Turquía', + 'TT' => 'Trinidad y Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan (Provincia de China)', + 'TZ' => 'República Unida de Tanzania', + 'UA' => 'Ucrania', + 'UG' => 'Uganda', + 'UM' => 'Islas Ultramarinas Menores de Estados Unidos', + 'US' => 'Estados Unidos', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistán', + 'VA' => 'Santa Sede (Ciudad Estado del Vaticano)', + 'VC' => 'San Vicente y las Granadinas', + 'VE' => 'República Bolivariana de Venezuela', + 'VG' => 'Islas Vírgenes Británicas', + 'VI' => 'Islas Vírgenes de los Estados Unidos.', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis y Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'Sudáfrica', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabue', +]; diff --git a/modules/Admin/Language/es/Dashboard.php b/modules/Admin/Language/es/Dashboard.php new file mode 100644 index 00000000..e797f0a0 --- /dev/null +++ b/modules/Admin/Language/es/Dashboard.php @@ -0,0 +1,28 @@ + 'Panel de control', + 'welcome_message' => '¡Bienvenid@ al área de administración!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Podcasts sin publicar', + 'last_published' => 'Últimas publicaciones en {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodios', + 'not_found' => 'Episodios sin publicar', + 'last_published' => 'Últimas publicaciones en {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Almacenamiento', + 'subtitle' => '{totalUploaded} de {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/es/Episode.php b/modules/Admin/Language/es/Episode.php new file mode 100644 index 00000000..48f93ad4 --- /dev/null +++ b/modules/Admin/Language/es/Episode.php @@ -0,0 +1,225 @@ + 'Temporada {seasonNumber}', + 'season_abbr' => 'T{seasonNumber}', + 'number' => 'Episodio {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Temporada {seasonNumber} episodio {episodeNumber}', + 'season_episode_abbr' => 'T{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comentario} + other {# comentarios} + }', + 'all_podcast_episodes' => 'Todos los episodios del podcast', + 'back_to_podcast' => 'Regresar al podcast', + 'edit' => 'Editar', + 'preview' => 'Preview', + 'publish' => 'Publicar', + 'publish_edit' => 'Editar publicación', + 'publish_date_edit' => 'Editar fecha de publicación', + 'unpublish' => 'Anular publicación', + 'publish_error' => 'El episodio ya está publicado.', + 'publish_edit_error' => 'El episodio ya está publicado.', + 'publish_cancel_error' => 'El episodio ya está publicado.', + 'publish_date_edit_error' => 'El episodio no ha sido publicado todavía, no puede editar su fecha de publicación.', + 'publish_date_edit_future_error' => '¡La fecha de publicación del episodio sólo puede establecerse a una fecha pasada! Si desea reprogramarla, despublicarla primero.', + 'publish_date_edit_success' => '¡La fecha de publicación del episodio se ha actualizado con éxito!', + 'unpublish_error' => 'El episodio no está publicado.', + 'delete' => 'Borrar', + 'go_to_page' => 'Ir a la página', + 'create' => 'Añadir un episodio', + 'publication_status' => [ + 'published' => 'Publicado', + 'with_podcast' => 'Publicado', + 'scheduled' => 'Programado', + 'not_published' => 'No publicado', + ], + 'with_podcast_hint' => 'A publicar al mismo tiempo que el podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Buscar un episodio', + 'clear' => 'Limpiar la búsqueda', + 'submit' => 'Buscar', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episodio} + other {# episodios} + }', + 'episode' => 'Episodio', + 'visibility' => 'Visibilidad', + 'downloads' => 'Descargas', + 'comments' => 'Comentarios', + 'actions' => 'Acciones', + ], + 'messages' => [ + 'createSuccess' => '¡El episodio ha sido creado correctamente!', + 'editSuccess' => '¡El episodio ha sido actualizado correctamente!', + 'publishSuccess' => '{publication_status, select, + published {¡Episodio publicado con éxito!} + scheduled {¡Publicación del episodio programada con éxito!} + with_podcast {Este episodio se publicará al mismo tiempo que el podcast.} + other {Este episodio no está publicado.} + }', + 'publishCancelSuccess' => '¡La publicación del episodio ha sido cancelada correctamente!', + 'unpublishBeforeDeleteTip' => 'Debe anular la publicación del episodio antes de eliminarlo.', + 'scheduleDateError' => '¡Se debe definir una fecha de publicación!', + 'deletePublishedEpisodeError' => 'Por favor, anule la publicación del episodio antes de eliminarlo.', + 'deleteSuccess' => '¡Episodio eliminado con éxito!', + 'deleteError' => 'Error al eliminar episodio {type, select, + transcript {transcripción} + chapters {capítulos} + image {portada} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Ya existe un episodio con el slug elegido.', + ], + 'form' => [ + 'file_size_error' => + '¡El tamaño de tu archivo es demasiado grande! El tamaño máximo es {0}. Aumenta los valores de `memory_limit`, `upload_max_filesize` y `post_max_size` en tu archivo de configuración php y reinicia tu servidor web para subir tu archivo.', + 'audio_file' => 'Archivo de audio', + 'audio_file_hint' => 'Elija un archivo de audio .mp3 o .m4a.', + 'info_section_title' => 'Información de episodio', + 'cover' => 'Portada del episodio', + 'cover_hint' => + 'Si no establece una portada, la portada del podcast se utilizará en su lugar.', + 'cover_size_hint' => 'La portada debe ser cuadrada con al menos 1400 px de ancho y alto.', + 'title' => 'Título', + 'title_hint' => + 'Debe contener un nombre de episodio claro y conciso. No especifique los números de episodio o temporada aquí.', + 'permalink' => 'Enlace permanente', + 'season_number' => 'Temporada', + 'episode_number' => 'Episodio', + 'type' => [ + 'label' => 'Tipo', + 'full' => 'Completo', + 'full_hint' => 'Contenido completo (el episodio)', + 'trailer' => 'Avance', + 'trailer_hint' => 'Pequeña pieza promocional de contenido que representa una vista previa de la serie actual', + 'bonus' => 'Extra', + 'bonus_hint' => 'Contenido extra para la serie (por ejemplo, detrás de escenas o entrevistas con el elenco) o contenido promocional para otra serie', + ], + 'premium_title' => 'Premium', + 'premium' => 'El episodio debe ser accesible solamente para los suscriptores premium', + 'parental_advisory' => [ + 'label' => 'Aviso parental', + 'hint' => '¿El episodio contiene contenido explícito?', + 'undefined' => 'indefinido', + 'clean' => 'Limpio', + 'explicit' => 'Explícito', + ], + 'show_notes_section_title' => 'Mostrar notas', + 'show_notes_section_subtitle' => + 'Hasta 4000 caracteres, sea claro y conciso. Muestre notas que ayudan a los potenciales oyentes a encontrar el episodio.', + 'description' => 'Descripción', + 'description_footer' => 'Descripción al pie', + 'description_footer_hint' => + 'Este texto se añade al final de cada descripción de episodios, es un buen lugar para introducir sus enlaces sociales, por ejemplo.', + 'additional_files_section_title' => 'Archivos adicionales', + 'additional_files_section_subtitle' => + 'Estos archivos pueden ser utilizados por otras plataformas para proporcionar una mejor experiencia a su audiencia. Vea {podcastNamespaceLink} para más información.', + 'location_section_title' => 'Ubicación', + 'location_section_subtitle' => '¿De qué lugar trata este episodio?', + 'location_name' => 'Nombre o dirección de ubicación', + 'location_name_hint' => 'Esta puede ser una ubicación real o ficticia', + 'transcript' => 'Transcripción (subtítulos / subtítulos ocultos)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Descargar transcripción', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Url remota para transcripción', + 'transcript_file_delete' => 'Eliminar archivo de transcripción', + 'chapters' => 'Capítulos', + 'chapters_hint' => 'El archivo debe estar en formato Capítulos JSON.', + 'chapters_download' => 'Descargar capítulos', + 'chapters_file' => 'Archivo de capítulos', + 'chapters_remote_url' => 'Url remota para el archivo de capítulos', + 'chapters_file_delete' => 'Eliminar archivo de capítulos', + 'advanced_section_title' => 'Parámetros Avanzados', + 'advanced_section_subtitle' => + 'Si necesita etiquetas RSS que Castopod no maneja, póngalas aquí.', + 'custom_rss' => 'Etiquetas RSS personalizadas para el episodio', + 'custom_rss_hint' => 'Esto se inyectará dentro de la etiqueta del {item}.', + 'block' => 'El episodio debe ocultarse a los catálogos públicos', + 'block_hint' => + 'El estado de visibilidad del episodio: al activar esto se impide que el episodio aparezca en Apple Podcasts, Google Podcasts y cualquier aplicación de terceros que extraiga episodios de estos directorios. (no está garantizado al 100%)', + 'submit_create' => 'Crear episodio', + 'submit_edit' => 'Guardar episodio', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Volver al panel del episodio', + 'post' => 'Tu post de anuncio', + 'post_hint' => + "Escribe un mensaje para anunciar la publicación de tu episodio. El mensaje será transmitido a todos tus seguidores en el fediverse y aparecerá en la página principal de tu podcast.", + 'message_placeholder' => 'Escribe tu mensaje…', + 'publication_date' => 'Fecha de publicación', + 'publication_method' => [ + 'now' => 'Ahora', + 'schedule' => 'Programar', + 'with_podcast' => 'Publicar junto al podcast', + ], + 'scheduled_publication_date' => 'Fecha programada de publicación', + 'scheduled_publication_date_clear' => 'Borrar fecha de publicación', + 'scheduled_publication_date_hint' => + 'Puede programar la versión de episodio estableciendo una fecha futura de publicación. Este campo debe ser formateado como YYYY-MM-DD HH:mm', + 'submit' => 'Publicar', + 'submit_edit' => 'Editar publicación', + 'cancel_publication' => 'Cancelar publicación', + 'message_warning' => 'No has escrito un mensaje para el anuncio tu publicación!', + 'message_warning_hint' => 'Tener un mensaje aumenta el alcance social, resultando en una mejor visibilidad para tu episodio.', + 'message_warning_submit' => 'Publicar de todos modos', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nueva fecha de publicación', + 'new_publication_date_hint' => 'Debe establecerse en una fecha pasada.', + 'submit' => 'Editar fecha de publicación', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Al anular la publicación del episodio se eliminarán todos los comentarios y mensajes asociados a él y el episodio será eliminado del feed RSS del podcast.", + 'understand' => 'Lo entiendo, quiero anular la publicación del episodio', + 'submit' => 'Anular publicación', + ], + 'delete_form' => [ + 'disclaimer' => + "Eliminar el episodio eliminará todos los archivos multimedia, comentarios, video clips y sonidos asociados a él.", + 'understand' => 'Entiendo, quiero eliminar el episodio', + 'submit' => 'Borrar', + ], + 'embed' => [ + 'title' => 'Reproductor embebido', + 'label' => + 'Elige un color de tema, copia el reproductor incrustable al portapapeles y pégalo en tu sitio web.', + 'clipboard_iframe' => 'Copiar reproductor incrustable al portapapeles', + 'clipboard_url' => 'Copiar dirección al portapapeles', + 'dark' => 'Oscuro', + 'dark-transparent' => 'Transparente oscuro', + 'light' => 'Claro', + 'light-transparent' => 'Transparente claro', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/es/EpisodeNavigation.php b/modules/Admin/Language/es/EpisodeNavigation.php new file mode 100644 index 00000000..af45950b --- /dev/null +++ b/modules/Admin/Language/es/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Ver página de episodios', + 'dashboard' => 'Panel de episodios', + 'episode-view' => 'Inicio', + 'episode-edit' => 'Editar episodio', + 'episode-persons-manage' => 'Administrar personas', + 'embed-add' => 'Reproductor embebido', + 'clips' => 'Recortes', + 'video-clips-list' => 'Recortes de vídeo', + 'video-clips-create' => 'Nuevo recorte de video', + 'soundbites-list' => 'Fragmentos de sonido', + 'soundbites-create' => 'Nuevo fragmento de sonido', +]; diff --git a/modules/Admin/Language/es/Fediverse.php b/modules/Admin/Language/es/Fediverse.php new file mode 100644 index 00000000..6d5b91b9 --- /dev/null +++ b/modules/Admin/Language/es/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => '¡No se pudo encontrar la cuenta!', + 'blockActorSuccess' => '¡{actor} ha sido bloqueado!', + 'unblockActorSuccess' => '¡El actor ha sido desbloqueado!', + 'blockDomainSuccess' => '¡{domain} ha sido bloqueado!', + 'unblockDomainSuccess' => '¡{domain} ha sido desbloqueado!', + ], + 'blocked_actors' => 'Cuentas bloqueadas', + 'blocked_domains' => 'Dominios bloqueados', + 'block_lists_form' => [ + 'handle' => 'Alias de la cuenta', + 'handle_hint' => 'Ingrese la cuenta @username@dominio.', + 'domain' => 'Nombre de dominio', + 'submit' => 'Bloquear!', + ], + 'list' => [ + 'actor' => 'Cuenta', + 'domain' => 'Nombre de dominio', + 'unblock' => 'Desbloquear', + ], +]; diff --git a/modules/Admin/Language/es/Home.php b/modules/Admin/Language/es/Home.php new file mode 100644 index 00000000..4bff23a7 --- /dev/null +++ b/modules/Admin/Language/es/Home.php @@ -0,0 +1,14 @@ + 'Todos los podcasts', + 'no_podcast' => 'No se encontró el podcast', +]; diff --git a/modules/Admin/Language/es/Install.php b/modules/Admin/Language/es/Install.php new file mode 100644 index 00000000..e7d7d095 --- /dev/null +++ b/modules/Admin/Language/es/Install.php @@ -0,0 +1,61 @@ + 'Configuración manual', + 'manual_config_subtitle' => + 'Crea un archivo `.env` con tus ajustes y actualiza la página para continuar la instalación.', + 'form' => [ + 'instance_config' => 'Configuración de instancia', + 'hostname' => 'Nombre de host', + 'media_base_url' => 'URL del reproductor de medios', + 'media_base_url_hint' => + 'Si utiliza un CDN y/o un servicio de análisis externo, puede establecerlo aquí.', + 'admin_gateway' => 'Pasarela de administración', + 'admin_gateway_hint' => + 'La ruta para acceder al área de administración (por ejemplo, https://example.com/cp-admin). Se establece por defecto como cp-admin, le recomendamos que lo cambie por razones de seguridad.', + 'auth_gateway' => 'Pasarela de autenticación', + 'auth_gateway_hint' => + 'La ruta para acceder al área de administración (por ejemplo, https://example.com/cp-auth). Se establece por defecto como cp-admin, le recomendamos que lo cambie por razones de seguridad.', + 'database_config' => 'Configuración de la base de datos', + 'database_config_hint' => + 'Castopod necesita conectarse a su base de datos MySQL (o MariaDB). Si no tiene esta información requerida, póngase en contacto con el administrador de su servidor.', + 'db_hostname' => 'Nombre de host de la base de datos', + 'db_name' => 'Nombre de la base de datos', + 'db_username' => 'Usuario la de base de datos', + 'db_password' => 'Contraseña de la base de datos', + 'db_prefix' => 'Prefijo de la base de datos', + 'db_prefix_hint' => + "El prefijo de los nombres de la tabla de Castopod, déjalo como aparece si no sabes lo que significa.", + 'cache_config' => 'Configuración de caché', + 'cache_config_hint' => + 'Elija su gestor de caché preferido. Déjelo como el valor predeterminado si no tiene ni idea de lo que significa.', + 'cache_handler' => 'Gestor de cache', + 'cacheHandlerOptions' => [ + 'file' => 'Archivo', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Siguiente', + 'submit' => 'Finalizar la instalación', + 'create_superadmin' => 'Crear la cuenta de administración', + 'email' => 'Correo electrónico', + 'username' => 'Nombre de usuario', + 'password' => 'Contraseña', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Tu cuenta de superadmin se ha creado correctamente. ¡Inicia sesión para empezar a hacer podcasting!', + 'databaseConnectError' => + 'Castopod no pudo conectarse a su base de datos. Edite la configuración de la base de datos y vuelva a intentarlo.', + 'writeError' => + "No se pudo crear/escribir el archivo `.env`. Debes crearlo manualmente siguiendo la plantilla de archivo `.env.example` en el paquete Castopod.", + ], +]; diff --git a/modules/Admin/Language/es/Navigation.php b/modules/Admin/Language/es/Navigation.php new file mode 100644 index 00000000..c8936b27 --- /dev/null +++ b/modules/Admin/Language/es/Navigation.php @@ -0,0 +1,44 @@ + 'Ocultar/mostrar barra lateral', + 'go_to_website' => 'Ir al sitio web', + 'go_to_admin' => 'Ir al panel de administración', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Panel de control', + 'admin' => 'Inicio', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Todos los podcasts', + 'podcast-create' => 'Nuevo podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Personas', + 'person-list' => 'Todas las personas', + 'person-create' => 'Nueva persona', + 'fediverse' => 'Fediverso', + 'fediverse-blocked-actors' => 'Cuentas bloqueadas', + 'fediverse-blocked-domains' => 'Dominios bloqueados', + 'users' => 'Usuarios', + 'user-list' => 'Todos los usuarios', + 'user-create' => 'Nuevo usuario', + 'pages' => 'Páginas', + 'page-list' => 'Todas las páginas', + 'page-create' => 'Página nueva', + 'settings' => 'Configuración', + 'settings-general' => 'General', + 'settings-theme' => 'Tema', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'Mi cuenta', + 'change-password' => 'Cambiar contraseña', + 'logout' => 'Cerrar sesión', + ], +]; diff --git a/modules/Admin/Language/es/Notifications.php b/modules/Admin/Language/es/Notifications.php new file mode 100644 index 00000000..70e375fb --- /dev/null +++ b/modules/Admin/Language/es/Notifications.php @@ -0,0 +1,19 @@ + 'Notificaciones', + 'reply' => '{actor_username} respondió a tu publicación', + 'favourite' => '{actor_username} ha marcado como favorita tu publicación', + 'reblog' => '{actor_username} ha compartido tu publicación', + 'follow' => '{actor_username} ha empezado a seguirte', + 'no_notifications' => 'No hay notificaciones', + 'mark_all_as_read' => 'Marcar todas como leídas', +]; diff --git a/modules/Admin/Language/es/Page.php b/modules/Admin/Language/es/Page.php new file mode 100644 index 00000000..f745b361 --- /dev/null +++ b/modules/Admin/Language/es/Page.php @@ -0,0 +1,30 @@ + 'Volver al inicio', + 'page' => 'Página', + 'all_pages' => 'Todas las páginas', + 'create' => 'Nueva página', + 'go_to_page' => 'Ir a la página', + 'edit' => 'Editar página', + 'delete' => 'Eliminar página', + 'form' => [ + 'title' => 'Título', + 'permalink' => 'Enlace permanente', + 'content' => 'Contenido', + 'submit_create' => 'Crear página', + 'submit_edit' => 'Guardar', + ], + 'messages' => [ + 'createSuccess' => '¡La página “{pageTitle}” fue creada con éxito!', + 'editSuccess' => 'La página se ha actualizado correctamente!', + ], +]; diff --git a/modules/Admin/Language/es/Pager.php b/modules/Admin/Language/es/Pager.php new file mode 100644 index 00000000..2bcbcd45 --- /dev/null +++ b/modules/Admin/Language/es/Pager.php @@ -0,0 +1,21 @@ + 'Navegación de página', + 'first' => 'Primero', + 'previous' => 'Anterior', + 'next' => 'Siguiente', + 'last' => 'Ultimo', + 'older' => 'Más antiguo', + 'newer' => 'Más nuevo', + 'invalidTemplate' => '{0} no es una plantilla de paginador válida.', + 'invalidPaginationGroup' => '{0} no es un grupo de paginación válido.', +]; diff --git a/modules/Admin/Language/es/Person.php b/modules/Admin/Language/es/Person.php new file mode 100644 index 00000000..c9e4c1a6 --- /dev/null +++ b/modules/Admin/Language/es/Person.php @@ -0,0 +1,65 @@ + 'Personas', + 'all_persons' => 'Todas las personas', + 'no_person' => 'No se encontró a nadie!', + 'create' => 'Crear una nueva persona', + 'view' => 'Ver persona', + 'edit' => 'Editar persona', + 'delete' => 'Eliminar persona', + 'messages' => [ + 'createSuccess' => '¡El episodio ha sido creado correctamente!', + 'editSuccess' => '¡El episodio ha sido actualizado correctamente!', + 'deleteSuccess' => '¡La persona ha sido eliminada!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'El avatar debe ser cuadrado y al menos 400 px de ancho y alto.', + 'full_name' => 'Nombre completo', + 'full_name_hint' => 'Este es el nombre completo o el alias de la persona.', + 'unique_name' => 'Nombre único', + 'unique_name_hint' => 'Utilizado para URLs', + 'information_url' => 'URL de información', + 'information_url_hint' => + 'Url a un recurso relevante de información sobre la persona, como una página de inicio o una plataforma de perfil de terceros.', + 'submit_create' => 'Crear una nueva persona', + 'submit_edit' => 'Guardar persona', + ], + 'podcast_form' => [ + 'title' => 'Administrar personas', + 'add_section_title' => 'Añadir personas a este podcast', + 'add_section_subtitle' => 'Usted puede elegir varias personas y roles.', + 'persons' => 'Personas', + 'persons_hint' => + 'Usted puede seleccionar una o varias personas con los mismos roles. Necesitas crear primero las personas.', + 'roles' => 'Roles', + 'roles_hint' => + 'No puedes seleccionar ninguno, uno o varios roles para una persona.', + 'submit_add' => 'Añadir persona(s)', + 'remove' => 'Eliminar', + ], + 'episode_form' => [ + 'title' => 'Administrar personas', + 'add_section_title' => 'Añadir personas a este episodio', + 'add_section_subtitle' => 'Usted puede elegir varias personas y roles.', + 'persons' => 'Personas', + 'persons_hint' => + 'Usted puede seleccionar una o varias personas con los mismos roles.', + 'roles' => 'Roles', + 'roles_hint' => + 'No puedes seleccionar ninguno, uno o varios roles para una persona.', + 'submit_add' => 'Añadir persona(s)', + 'remove' => 'Eliminar', + ], + 'credits' => 'Créditos', +]; diff --git a/modules/Admin/Language/es/Platforms.php b/modules/Admin/Language/es/Platforms.php new file mode 100644 index 00000000..f045e36c --- /dev/null +++ b/modules/Admin/Language/es/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Ir al sitio web de {platformName}', + 'register' => 'Register', + 'submit_url' => 'Envía tu podcast en {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => '¿Mostrar en la página de inicio del podcast?', + 'on_embed' => '¿Mostrar en el reproductor incrustable?', + 'remove' => 'Eliminar {platformName}', + 'submit' => 'Guardar', + 'messages' => [ + 'updateSuccess' => '¡Los enlaces de la plataforma se han actualizado correctamente!', + 'removeLinkSuccess' => 'El enlace de la plataforma ha sido eliminado.', + 'removeLinkError' => + 'No se ha podido eliminar el enlace de la plataforma. Inténtalo de nuevo.', + ], + 'description' => [ + 'podcasting' => 'El ID del podcast en esta plataforma', + 'social' => 'El ID de la cuenta del podcast en esta plataforma', + 'funding' => 'Mensaje de llamada a la acción', + ], +]; diff --git a/modules/Admin/Language/es/Podcast.php b/modules/Admin/Language/es/Podcast.php new file mode 100644 index 00000000..3786cfda --- /dev/null +++ b/modules/Admin/Language/es/Podcast.php @@ -0,0 +1,330 @@ + 'Todos los podcasts', + 'no_podcast' => 'No se encontró el podcast!', + 'create' => 'Crear podcasts', + 'import' => 'Importar un podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Nuevo episodio', + 'view' => 'Ver Podcast', + 'edit' => 'Editar el Podcast', + 'publish' => 'Publicar podcast', + 'publish_edit' => 'Editar la publicación', + 'delete' => 'Eliminar podcast', + 'see_episodes' => 'Ver episodios', + 'see_contributors' => 'Ver colaboradores', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Ir a la página', + 'latest_episodes' => 'Últimos Episodios', + 'see_all_episodes' => 'Mostrar todos los episodios', + 'draft' => 'Borrador', + 'messages' => [ + 'createSuccess' => '¡El Podcast ha sido creado con éxito!', + 'editSuccess' => 'El Podcast se ha actualizado correctamente!', + 'importSuccess' => 'El Podcast se ha importado correctamente!', + 'deleteSuccess' => '¡El Podcast @{podcast_handle} ha sido eliminado con éxito!', + 'deletePodcastMediaError' => 'No se ha podido eliminar {type, select, + cover {la portada} + banner {el cartel} + other {el material} + } del podcast.', + 'deleteEpisodeMediaError' => 'No se ha podido elminar {type, select, + transcript {la transcripción} + chapters {los episodios} + image {la portada} + audio {el audio} + other {el material} + } del episodio {episode_slug}.', + 'deletePodcastMediaFolderError' => 'No se pudo eliminar la carpeta del material del podcast {folder_path}. Puedes eliminarla manualmente del disco.', + 'podcastFeedUpdateSuccess' => '¡Actualización exitosa: {number_of_new_episodes, plural, + one {se ha añadido un episodio} + other {se han añadido # episodios} + } al podcast!', + 'podcastFeedUpToDate' => 'El Podcast ya está actualizado.', + 'publishError' => 'Este podcast ya ha sido publicado o está programado para su publicación.', + 'publishEditError' => 'Este podcast no está programado para ser publicado.', + 'publishCancelSuccess' => '¡La publicación del podcast ha sido cancelada con éxito!', + 'scheduleDateError' => '¡Se debe definir una fecha de publicación!', + ], + 'form' => [ + 'identity_section_title' => 'Identidad de Podcast', + 'identity_section_subtitle' => 'Estos campos le permiten recibir un aviso.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Portada de Podcast', + 'cover_size_hint' => 'La portada debe ser cuadrada y con al menos 1400 px de ancho y alto.', + 'banner' => 'Cartel del Podcast', + 'banner_size_hint' => 'El cartel debe tener una relación de 3:1 con al menos 1500 px de ancho.', + 'banner_delete' => 'Borrar el cartel del podcast', + 'title' => 'Título', + 'handle' => 'Alias', + 'handle_hint' => + 'Se utiliza para identificar el podcast. Se aceptan mayúsculas, minúsculas, números y guiones bajos.', + 'type' => [ + 'label' => 'Tipo', + 'episodic' => 'Por episodios', + 'episodic_hint' => 'Si los episodios están destinados a ser consumidos sin ningún orden específico. Los episodios más nuevos serán presentados primero.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Descripción', + 'classification_section_title' => 'Clasificación', + 'classification_section_subtitle' => + 'Estos campos impactarán a su audiencia y competencia.', + 'language' => 'Idioma', + 'category' => 'Categoría', + 'category_placeholder' => 'Selecciona una categoría…', + 'other_categories' => 'Otras categorías', + 'parental_advisory' => [ + 'label' => 'Aviso parental', + 'hint' => '¿Contiene contenido explícito?', + 'undefined' => 'indefinido', + 'clean' => 'Limpio', + 'explicit' => 'Explícito', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => '¿Quién está gestionando el podcast?', + 'owner_name' => 'Nombre del propietario', + 'owner_name_hint' => + 'Para uso administrativo solamente. Visible en la fuente pública RSS.', + 'owner_email' => 'Email del propietario', + 'owner_email_hint' => + 'Será utilizado por la mayoría de las plataformas para verificar la propiedad del podcast. Visible en el feed RSS público.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publicador', + 'publisher_hint' => + 'El grupo responsable de la creación del espectáculo. A menudo se refiere a la empresa matriz o red de un podcast. Este campo a veces se etiqueta como \'Autor\'.', + 'copyright' => 'Derechos de autor', + 'location_section_title' => 'Ubicación', + 'location_section_subtitle' => '¿De qué lugar trata este podcast?', + 'location_name' => 'Nombre o dirección de ubicación', + 'location_name_hint' => 'Este puede ser un lugar real o ficticio', + 'monetization_section_title' => 'Monetización', + 'monetization_section_subtitle' => + 'Gana dinero gracias a tu audiencia.', + 'premium' => 'Premium', + 'premium_by_default' => 'Los episodios deben establecerse como premium por defecto', + 'premium_by_default_hint' => 'Los episodios Podcast se marcarán como premium de forma predeterminada. Todavía puedes elegir establecer algunos episodios, trailers o bonificaciones como públicos.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Analiza tus datos de estadísticas con OP3, un servicio de analíticas fiable y de código abierto. Comparte, valida y compara tus estadísticas con el ecosistema de podcasting abierto.', + 'op3_enable' => 'Activa el servicio de estadísticas OP3', + 'op3_enable_hint' => 'Por motivos de seguridad, las estadísticas de los episodios premium no serán compartidas con OP3.', + 'payment_pointer' => 'Puntero de pago para Monetización web', + 'payment_pointer_hint' => + 'Aquí es donde usted recibirá dinero gracias a la Monetización Web', + 'advanced_section_title' => 'Parámetros Avanzados', + 'advanced_section_subtitle' => + 'Si necesita etiquetas RSS que Castopod no maneja, póngalas aquí.', + 'custom_rss' => 'Etiquetas RSS personalizadas para el podcast', + 'custom_rss_hint' => 'Esto se inyectará dentro de la etiqueta de canal.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Nueva URL de feed', + 'new_feed_url_hint' => 'Utilice este campo cuando se mueva a otro dominio o plataforma de alojamiento podcast. De forma predeterminada, el valor se establece en la URL actual de RSS si el podcast es importado.', + 'old_feed_url' => 'Antigua URL del feed RSS', + 'partnership' => 'Asociación', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL del enlace', + 'partner_image_url' => 'URL de la imágen', + 'partner_id_hint' => 'Su propio ID de socio', + 'partner_link_url_hint' => 'La dirección genérica de enlace de socio', + 'partner_image_url_hint' => 'La dirección de imagen genérica del socio', + 'block' => 'El podcast debe ocultarse a los catálogos públicos', + 'block_hint' => + 'El estado de visibilidad del podcast: al activar esto se impide que este podcast al completo aparezca en Apple Podcasts, Google Podcasts y cualquier aplicación de terceros que extraiga episodios de estos directorios. (no está garantizado al 100%)', + 'complete' => 'El Podcast no tendrá nuevos episodios', + 'lock' => 'Evitar que el podcast sea copiado', + 'lock_hint' => + 'El propósito es decirle a otras plataformas de podcast si se les permite importar este feed. Un valor de sí significa que cualquier intento de importar este feed en una nueva plataforma debe ser rechazado.', + 'submit_create' => 'Crear podcasts', + 'submit_edit' => 'Guardar podcast', + ], + 'category_options' => [ + 'uncategorized' => 'sin categoría', + 'arts' => 'Artes', + 'business' => 'Negocios', + 'comedy' => 'Comedia', + 'education' => 'Educación', + 'fiction' => 'Ficción', + 'government' => 'Gubernamental', + 'health_and_fitness' => 'Salud & Bienestar', + 'history' => 'Historia', + 'kids_and_family' => 'Niños y Familia', + 'leisure' => 'Ocio', + 'music' => 'Música', + 'news' => 'Noticias', + 'religion_and_spirituality' => 'Religión y espiritualidad', + 'science' => 'Ciencias', + 'society_and_culture' => 'Sociedad y cultura', + 'sports' => 'Deportes', + 'technology' => 'Tecnología', + 'true_crime' => 'Crimen verdadero', + 'tv_and_film' => 'TV & Cine', + 'books' => 'Libros', + 'design' => 'Diseño', + 'fashion_and_beauty' => 'Moda & Belleza', + 'food' => 'Alimentos', + 'performing_arts' => 'Artes Escénicas', + 'visual_arts' => 'Artes visuales', + 'careers' => 'Empleos', + 'entrepreneurship' => 'Emprendimiento', + 'investing' => 'Inversiones', + 'management' => 'Administración', + 'marketing' => 'Marketing', + 'non_profit' => 'Sin fines de lucro', + 'comedy_interviews' => 'Entrevistas de comedia', + 'improv' => 'Improvisación', + 'stand_up' => 'Stand-Up', + 'courses' => 'Cursos', + 'how_to' => 'Como hacer', + 'language_learning' => 'Aprendizaje de idiomas', + 'self_improvement' => 'Crecimiento personal', + 'comedy_fiction' => 'Comedia de Ficción', + 'drama' => 'Drama', + 'science_fiction' => 'Ciencia Ficción', + 'alternative_health' => 'Salud alternativa', + 'fitness' => 'Fitness', + 'medicine' => 'Medicina', + 'mental_health' => 'Salud mental', + 'nutrition' => 'Nutrición', + 'sexuality' => 'Sexualidad', + 'education_for_kids' => 'Educación para Niños', + 'parenting' => 'Paternidad', + 'pets_and_animals' => 'Mascotas y animales', + 'stories_for_kids' => 'Historias para niños', + 'animation_and_manga' => 'Animación y Manga', + 'automotive' => 'Automotor', + 'aviation' => 'Aviación', + 'crafts' => 'Creaciones', + 'games' => 'Juegos', + 'hobbies' => 'Pasatiempos', + 'home_and_garden' => 'Hogar y jardín', + 'video_games' => 'Video Juegos', + 'music_commentary' => 'Comentario de música', + 'music_history' => 'Historia de Música', + 'music_interviews' => 'Entrevistas de Música', + 'business_news' => 'Noticias de negocios', + 'daily_news' => 'Noticias diarias', + 'entertainment_news' => 'Noticias de Entretenimiento', + 'news_commentary' => 'Comentario de Noticias', + 'politics' => 'Política', + 'sports_news' => 'Noticias deportivas', + 'tech_news' => 'Noticias de Tecnología', + 'buddhism' => 'Budismo', + 'christianity' => 'Cristianismo', + 'hinduism' => 'Hinduismo', + 'islam' => 'Islam', + 'judaism' => 'Judaismo', + 'religion' => 'Religión', + 'spirituality' => 'Espiritualidad', + 'astronomy' => 'Astronomía', + 'chemistry' => 'Química', + 'earth_sciences' => 'Ciencias de la Tierra', + 'life_sciences' => 'Ciencias Biológicas', + 'mathematics' => 'Matemáticas', + 'natural_sciences' => 'Ciencias Naturales', + 'nature' => 'Naturaleza', + 'physics' => 'Física', + 'social_sciences' => 'Ciencias Sociales', + 'documentary' => 'Documentales', + 'personal_journals' => 'Diario personal', + 'philosophy' => 'Filosofía', + 'places_and_travel' => 'Lugares & Viajes', + 'relationships' => 'Relaciones', + 'baseball' => 'Beisbol', + 'basketball' => 'Baloncesto', + 'cricket' => 'Críquet', + 'fantasy_sports' => 'Deportes Fantásticos', + 'football' => 'Fútbol', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Correr', + 'soccer' => 'Fútbol', + 'swimming' => 'Natación', + 'tennis' => 'Tenis', + 'volleyball' => 'Voleibol', + 'wilderness' => 'Desierto', + 'wrestling' => 'Lucha Libre', + 'after_shows' => 'Después de los espectáculos', + 'film_history' => 'Historia del cine', + 'film_interviews' => 'Entrevistas de cine', + 'film_reviews' => 'Reseñas de cine', + 'tv_reviews' => 'Reseñas de TV', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Regresar al panel de control del podcast', + 'post' => 'Tu publicación de anuncio', + 'post_hint' => + "Escribe un mensaje para anunciar la publicación de tu podcast. El mensaje aparecerá destacado en la página principal del podcast.", + 'message_placeholder' => 'Redacta tu mensaje…', + 'submit' => 'Publicar', + 'publication_date' => 'Fecha de publicación', + 'publication_method' => [ + 'now' => 'Ahora', + 'schedule' => 'Programación', + ], + 'scheduled_publication_date' => 'Fecha de publicación programada', + 'scheduled_publication_date_hint' => + 'Puede programar el lanzamiento del podcast definiendo una fecha de publicación futura. Este campo debe ser formateado así YYYY-MM-DD HH:mm', + 'submit_edit' => 'Editar publicación', + 'cancel_publication' => 'Cancelar publicación', + 'message_warning' => '¡No has escrito un mensaje para el anuncio tu publicación!', + 'message_warning_hint' => 'Incluir un mensaje aumenta el interés en las redes sociales, resultando en una mayor visibilidad de tu podcast.', + 'message_warning_submit' => 'Publicar de todos modos', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'modo borrador', + 'not_published' => 'Este podcast aún no ha sido publicado.', + 'scheduled' => 'Este podcast está programado para su publicación el {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Al eliminar el podcast, se eliminarán todos los episodios, archivos multimedia, mensajes y estadísticas asociados a él. Esta acción es irreversible, no podrá recuperarlos después de la eliminación.", + 'understand' => 'Entiendo, quiero que el podcast sea eliminado permanentemente', + 'submit' => 'Eliminar', + ], + 'by' => 'Por {publisher}', + 'season' => 'Temporada {seasonNumber}', + 'list_of_episodes_year' => '{year} episodios ({episodeCount})', + 'list_of_episodes_season' => + 'Temporada {seasonNumber} episodios ({episodeCount})', + 'no_episode' => '¡No se encontró el episodio!', + 'follow' => 'Seguir', + 'followers' => '{numberOfFollowers, plural, + one {Un seguidor} + other {# seguidores} + }', + 'posts' => '{numberOfPosts, plural, + one {Una publicación} + other {# publicaciones} + }', + 'activity' => 'Actividad', + 'episodes' => 'Episodios', + 'sponsor' => 'Patrocinador', + 'funding_links' => 'Enlaces de financiación para {podcastTitle}', + 'find_on' => 'Buscar {podcastTitle} en', + 'listen_on' => 'Escuchar en', +]; diff --git a/modules/Admin/Language/es/PodcastNavigation.php b/modules/Admin/Language/es/PodcastNavigation.php new file mode 100644 index 00000000..43a142bb --- /dev/null +++ b/modules/Admin/Language/es/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Ir a la página del podcast', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Panel de Podcast', + 'podcast-view' => 'Inicio', + 'podcast-edit' => 'Editar podcast', + 'podcast-persons-manage' => 'Administrar personas', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodios', + 'episode-list' => 'Todos los episodios', + 'episode-create' => 'Nuevo episodio', + 'analytics' => 'Estadísticas', + 'podcast-analytics' => 'Vista general del público', + 'podcast-analytics-webpages' => 'Visitas a páginas web', + 'podcast-analytics-locations' => 'Ubicaciones', + 'podcast-analytics-unique-listeners' => 'Oyentes únicos', + 'podcast-analytics-players' => 'Reproductores', + 'podcast-analytics-listening-time' => 'Tiempo de escucha', + 'podcast-analytics-time-periods' => 'Periodos de tiempo', + 'monetization' => 'Monetization', + 'subscription-list' => 'Todas las suscripciones', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Colaboradores', + 'contributor-list' => 'Todos los colaboradores', + 'contributor-add' => 'Añadir colaborador', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Redes sociales', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/es/Settings.php b/modules/Admin/Language/es/Settings.php new file mode 100644 index 00000000..6c63c82d --- /dev/null +++ b/modules/Admin/Language/es/Settings.php @@ -0,0 +1,58 @@ + 'Configuración General', + 'instance' => [ + 'title' => 'Instancia', + 'site_icon' => 'Icono del sitio', + 'site_icon_delete' => 'Borrar icono del sitio', + 'site_icon_hint' => 'Los iconos del sitio son lo que ves en las pestañas del navegador, la barra de marcadores y cuando agregas un sitio web como un acceso directo en los dispositivos móviles.', + 'site_icon_helper' => 'El icono debe ser cuadrado con al menos 512 px de ancho y alto.', + 'site_name' => 'Nombre del sitio', + 'site_description' => 'Descripción del sitio', + 'submit' => 'Guardar', + 'editSuccess' => 'La instancia ha sido actualizada correctamente!', + 'deleteIconSuccess' => '¡El icono del sitio se ha eliminado con éxito!', + ], + 'images' => [ + 'title' => 'Imágenes', + 'subtitle' => 'Aquí puede regenerar todas las imágenes basadas en los originales que fueron subidos. Para ser usado si encuentras que faltan algunas imágenes. Esta tarea puede llevar un tiempo.', + 'regenerate' => 'Regenerar imágenes', + 'regenerationSuccess' => '¡Todas las imágenes han sido regeneradas con éxito!', + ], + 'housekeeping' => [ + 'title' => 'Mantenimiento', + 'subtitle' => 'Ejecuta varias tareas de limpieza. Usa esta función si alguna vez encuentras problemas con los archivos multimedia o la integridad de datos. Estas tareas pueden tardar algún tiempo.', + 'reset_counts' => 'Reiniciar contadores', + 'reset_counts_helper' => 'Esta opción recalculará y restablecerá todos los conteos de datos (número de seguidores, publicaciones, comentarios, …).', + 'rewrite_media' => 'Reescribir metadatos de medios', + 'rewrite_media_helper' => 'Esta opción eliminará todos los archivos multimedia superfluos y los volverá a crear (imágenes, archivos de audio, transcripciones, capítulos, …)', + 'rename_episodes_files' => 'Renombrar archivos de audio del episodio', + 'rename_episodes_files_hint' => 'Esta opción renombrará todos los archivos de audio de episodios a una cadena aleatoria de caracteres. Usa esto si uno de tus episodios privados fue filtrado ya que esto lo ocultará efectivamente.', + 'clear_cache' => 'Borrar toda la caché', + 'clear_cache_helper' => 'Esta opción eliminará la caché de redis o archivos de escritura/caché.', + 'run' => 'Ejecutar tareas de mantenimiento', + 'runSuccess' => '¡El mantenimiento se ha realizado con éxito!', + ], + 'theme' => [ + 'title' => 'Tema', + 'accent_section_title' => 'Color de acento', + 'accent_section_subtitle' => 'Elija el color para determinar la apariencia de todas las páginas públicas.', + 'pine' => 'Pino', + 'crimson' => 'Carmesí', + 'amber' => 'Ámbar', + 'lake' => 'Lago', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Guardar', + 'setInstanceThemeSuccess' => '¡El tema se ha actualizado con éxito!', + ], +]; diff --git a/modules/Admin/Language/es/Soundbite.php b/modules/Admin/Language/es/Soundbite.php new file mode 100644 index 00000000..6034f115 --- /dev/null +++ b/modules/Admin/Language/es/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Fragmentos de sonido', + 'soundbite' => 'Fragmento de sonido', + ], + 'messages' => [ + 'createSuccess' => '¡El fragmento de sonido ha sido creado con éxito!', + 'deleteSuccess' => '¡El fragmento de sonido ha sido eliminado con éxito!', + ], + 'form' => [ + 'title' => 'Nuevo fragmento de sonido', + 'soundbite_title' => 'Título del fragmento de sonido', + 'start_time' => 'Comenzar en', + 'duration' => 'Duración', + 'submit' => 'Crear fragmento de sonido', + ], + 'play' => 'Reproducir fragmento de sonido', + 'stop' => 'Detener fragmento de sonido', + 'create' => 'Nuevo fragmento de sonido', + 'delete' => 'Eliminar fragmento de sonido', +]; diff --git a/modules/Admin/Language/es/Validation.php b/modules/Admin/Language/es/Validation.php new file mode 100644 index 00000000..5478dfe8 --- /dev/null +++ b/modules/Admin/Language/es/Validation.php @@ -0,0 +1,17 @@ + + '{field} no es una imagen, o no es suficientemente ancha o alta.', + 'is_image_ratio' => + '{field} no es una imagen o no es de la proporción correcta.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/es/VideoClip.php b/modules/Admin/Language/es/VideoClip.php new file mode 100644 index 00000000..4eedadb1 --- /dev/null +++ b/modules/Admin/Language/es/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Recortes de vídeo', + 'status' => [ + 'label' => 'Estado', + 'queued' => 'en cola', + 'queued_hint' => 'El clip está esperando ser procesado.', + 'pending' => 'pendiente', + 'pending_hint' => 'El clip se generará en breve.', + 'running' => 'ejecutándose', + 'running_hint' => 'El clip se está generando.', + 'failed' => 'sin éxito', + 'failed_hint' => 'No se pudo generar el clip: fallo del script.', + 'passed' => 'aprobado', + 'passed_hint' => '¡El clip se ha generado correctamente!', + ], + 'clip' => 'Recorte', + 'duration' => 'Duración del trabajo', + ], + 'title' => 'Recorte de vídeo: {videoClipLabel}', + 'download_clip' => 'Descargar recorte', + 'create' => 'Nuevo recorte de video', + 'go_to_page' => 'Ir a la página del recorte', + 'retry' => 'Reintentar la generación de recorte', + 'delete' => 'Borrar recorte', + 'logs' => 'Registros de trabajo', + 'messages' => [ + 'alreadyExistingError' => 'El recorte de video que estás intentando crear ya existe!', + 'addToQueueSuccess' => 'El recorte de video ha sido añadido a la cola, ¡esperando ser creado!', + 'deleteSuccess' => 'El recorte de vídeo se ha eliminado con éxito!', + ], + 'format' => [ + 'landscape' => 'Horizontal', + 'portrait' => 'Vertical', + 'squared' => 'Cuadrado', + ], + 'form' => [ + 'title' => 'Nuevo recorte de video', + 'params_section_title' => 'Parámetros del recorte de video', + 'clip_title' => 'Titulo del recorte', + 'format' => [ + 'label' => 'Elija un formato', + 'landscape_hint' => 'Con una relación de 16:9, videos horizontales son excelentes para PeerTube, Youtube y Vimeo.', + 'portrait_hint' => 'Con una relación de 9:16, los videos verticales son excelentes para TikTok, los cortos de Youtube y las historias de Instagram.', + 'squared_hint' => 'Con una relación 1:1, los videos cuadrados son excelentes para Mastodon, Facebook, Twitter y LinkedIn.', + ], + 'theme' => 'Seleccionar un tema', + 'start_time' => 'Comenzar en', + 'duration' => 'Duración', + 'trim_start' => 'Recortar Inicio', + 'trim_end' => 'Recortar final', + 'submit' => 'Crear recorte de video', + ], + 'requirements' => [ + 'title' => 'Faltan requisitos', + 'missing' => 'Faltan requisitos. ¡Asegúrate de añadir todos los elementos necesarios para que se les permita crear un vídeo para este episodio!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Dibujo de Gráficos (GD)', + 'freetype' => 'Librería Freetype para GD', + 'transcript' => 'Archivo de transcripción (.srt)', + ], +]; diff --git a/modules/Admin/Language/eu/AboutCastopod.php b/modules/Admin/Language/eu/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/eu/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/eu/Breadcrumb.php b/modules/Admin/Language/eu/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/eu/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/eu/Charts.php b/modules/Admin/Language/eu/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/eu/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/eu/Common.php b/modules/Admin/Language/eu/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/eu/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/eu/Countries.php b/modules/Admin/Language/eu/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/eu/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/eu/Dashboard.php b/modules/Admin/Language/eu/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/eu/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/eu/Episode.php b/modules/Admin/Language/eu/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/eu/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/eu/EpisodeNavigation.php b/modules/Admin/Language/eu/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/eu/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/eu/Fediverse.php b/modules/Admin/Language/eu/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/eu/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/eu/Home.php b/modules/Admin/Language/eu/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/eu/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/eu/Install.php b/modules/Admin/Language/eu/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/eu/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/eu/Navigation.php b/modules/Admin/Language/eu/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/eu/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/eu/Notifications.php b/modules/Admin/Language/eu/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/eu/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/eu/Page.php b/modules/Admin/Language/eu/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/eu/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/eu/Pager.php b/modules/Admin/Language/eu/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/eu/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/eu/Person.php b/modules/Admin/Language/eu/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/eu/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/eu/Platforms.php b/modules/Admin/Language/eu/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/eu/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/eu/Podcast.php b/modules/Admin/Language/eu/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/eu/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/eu/PodcastNavigation.php b/modules/Admin/Language/eu/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/eu/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/eu/Settings.php b/modules/Admin/Language/eu/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/eu/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/eu/Soundbite.php b/modules/Admin/Language/eu/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/eu/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/eu/Validation.php b/modules/Admin/Language/eu/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/eu/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/eu/VideoClip.php b/modules/Admin/Language/eu/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/eu/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/fa/AboutCastopod.php b/modules/Admin/Language/fa/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/fa/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/fa/Admin.php b/modules/Admin/Language/fa/Admin.php new file mode 100644 index 00000000..5e394237 --- /dev/null +++ b/modules/Admin/Language/fa/Admin.php @@ -0,0 +1,15 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'choose_interact' => 'Choose how to interact', +]; diff --git a/modules/Admin/Language/fa/Breadcrumb.php b/modules/Admin/Language/fa/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/fa/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/fa/Charts.php b/modules/Admin/Language/fa/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/fa/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/fa/Common.php b/modules/Admin/Language/fa/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/fa/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/fa/Countries.php b/modules/Admin/Language/fa/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/fa/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/fa/Dashboard.php b/modules/Admin/Language/fa/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/fa/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/fa/Episode.php b/modules/Admin/Language/fa/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/fa/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/fa/EpisodeNavigation.php b/modules/Admin/Language/fa/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/fa/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/fa/Fediverse.php b/modules/Admin/Language/fa/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/fa/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/fa/Home.php b/modules/Admin/Language/fa/Home.php new file mode 100644 index 00000000..bc83fd98 --- /dev/null +++ b/modules/Admin/Language/fa/Home.php @@ -0,0 +1,14 @@ + 'تمامی پادکست‌ها', + 'no_podcast' => 'هیچ پادکستی پیدا نشد', +]; diff --git a/modules/Admin/Language/fa/Install.php b/modules/Admin/Language/fa/Install.php new file mode 100644 index 00000000..a2643d24 --- /dev/null +++ b/modules/Admin/Language/fa/Install.php @@ -0,0 +1,61 @@ + 'پیکربندی دستی', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'پیکربندی نمونه', + 'hostname' => 'نام میزبان', + 'media_base_url' => 'نشانی پایهٔ رسانه', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'دروازهٔ مدیر', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'دروازهٔ هویت‌سنجی', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'پیکربندی پایگاه داده', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'نام میزبان پایگاه داده', + 'db_name' => 'نام پایگاه‌داده', + 'db_username' => 'نام کاربری پایگاه‌داده', + 'db_password' => 'گذرواژهٔ پایگاه‌داده', + 'db_prefix' => 'پيشوند پايگاه‌داده', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'پیکربندی انباره', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'مدیر انباره', + 'cacheHandlerOptions' => [ + 'file' => 'پرونده', + 'redis' => 'ردیس', + 'predis' => 'Predis', + ], + 'next' => 'بعدی', + 'submit' => 'پایان نصب', + 'create_superadmin' => 'ایجاد حساب ابرمدیریتان', + 'email' => 'رایانامه', + 'username' => 'نام‌کاربری', + 'password' => 'گذرواژه', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/fa/Navigation.php b/modules/Admin/Language/fa/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/fa/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/fa/Notifications.php b/modules/Admin/Language/fa/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/fa/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/fa/Page.php b/modules/Admin/Language/fa/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/fa/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/fa/Pager.php b/modules/Admin/Language/fa/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/fa/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/fa/Person.php b/modules/Admin/Language/fa/Person.php new file mode 100644 index 00000000..3465af96 --- /dev/null +++ b/modules/Admin/Language/fa/Person.php @@ -0,0 +1,65 @@ + 'افراد', + 'all_persons' => 'تمامی افراد', + 'no_person' => 'هیچ‌کس پیدا نشد!', + 'create' => 'ایجاد یک نفر', + 'view' => 'دیدن فرد', + 'edit' => 'ویرایش فرد', + 'delete' => 'حذف فرد', + 'messages' => [ + 'createSuccess' => 'فرد با موفّقیت ساخته شد!', + 'editSuccess' => 'فرد با موفّقیت به‌روز شد!', + 'deleteSuccess' => 'فرد برداشته شد!', + ], + 'form' => [ + 'avatar' => 'چهرک', + 'avatar_size_hint' => + 'چهرک باید مربّعی بوده و کمینه ۴۰۰ پیکسل پنها و بلندا داشته باشد.', + 'full_name' => 'نام کامل', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'نام یکتا', + 'unique_name_hint' => 'استفاده شده برای نشانی‌ها', + 'information_url' => 'نشانی اطّلاعات', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'ایجاد فرد', + 'submit_edit' => 'ذخیرهٔ فرد', + ], + 'podcast_form' => [ + 'title' => 'مدیریت افراد', + 'add_section_title' => 'افزودن افراد به این پادکست', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'افراد', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'نقش‌ها', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'افزودن فرد(ها)', + 'remove' => 'برداشتن', + ], + 'episode_form' => [ + 'title' => 'مدیریت افراد', + 'add_section_title' => 'افزودن افراد به این قسمت', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'افراد', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'نقش‌ها', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'افزودن فرد(ها)', + 'remove' => 'برداشتن', + ], + 'credits' => 'اعتبارها', +]; diff --git a/modules/Admin/Language/fa/Platforms.php b/modules/Admin/Language/fa/Platforms.php new file mode 100644 index 00000000..7dc10de7 --- /dev/null +++ b/modules/Admin/Language/fa/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'رفتن به پایگاه وب {platformName}', + 'register' => 'Register', + 'submit_url' => 'ثبت پادکستتان روی {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'نمایش در صفحهٔ خانگی پادکست؟', + 'on_embed' => 'نمایش در پخش‌کنندهٔ تعبیه شده؟', + 'remove' => 'برداشتن {platformName}', + 'submit' => 'ذخیره', + 'messages' => [ + 'updateSuccess' => 'پیوندهای بن‌سازه با موفّقیت به‌روز شدند!', + 'removeLinkSuccess' => 'پیوند بن‌سازه برداشته شد.', + 'removeLinkError' => + 'پیوند بن‌سازه نتوانست برداشته شود. دوباره تلاش کنید.', + ], + 'description' => [ + 'podcasting' => 'شناسهٔ پادکست روی این بن‌سازه', + 'social' => 'شناسهٔ حساب پادکست روی این بن‌سازه', + 'funding' => 'پیام فراخوانی کنش', + ], +]; diff --git a/modules/Admin/Language/fa/Podcast.php b/modules/Admin/Language/fa/Podcast.php new file mode 100644 index 00000000..9b1f047e --- /dev/null +++ b/modules/Admin/Language/fa/Podcast.php @@ -0,0 +1,330 @@ + 'تمامی پادکست‌ها', + 'no_podcast' => 'هیچ پادکستی پیدا نشد!', + 'create' => 'ایجاد پادکست', + 'import' => 'درون‌ریزی پادکست', + 'all_imports' => 'درون‌ریزی‌های پادکست', + 'new_episode' => 'قسمت جدید', + 'view' => 'دیدن پادکست', + 'edit' => 'ویرایش پادکست', + 'publish' => 'انتشار پادکست', + 'publish_edit' => 'Edit publication', + 'delete' => 'حذف پادکست', + 'see_episodes' => 'دیدن قسمت‌ّا', + 'see_contributors' => 'دیدن مشارکت‌کنندگان', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'رفتن به صفحه', + 'latest_episodes' => 'جدیدترین قسمت‌ها', + 'see_all_episodes' => 'دیدن تمامی قسمت‌ها', + 'draft' => 'پیش‌نویس', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'هویت پادکست', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'جلد پادکست', + 'cover_size_hint' => 'جلد باید مربّعی بوده و کمینه ۱۴۰۰ پیکسل پنها و بلندا داشته باشد.', + 'banner' => 'بیرق پادکست', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'حذف بیرق پادکست', + 'title' => 'عنوان', + 'handle' => 'شناسه', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'گونه', + 'episodic' => 'قسمتی', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'سریالی', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'شرح', + 'classification_section_title' => 'طبقه‌بندی', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/fa/PodcastNavigation.php b/modules/Admin/Language/fa/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/fa/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/fa/Settings.php b/modules/Admin/Language/fa/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/fa/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/fa/Soundbite.php b/modules/Admin/Language/fa/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/fa/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/fa/Validation.php b/modules/Admin/Language/fa/Validation.php new file mode 100644 index 00000000..0659cd86 --- /dev/null +++ b/modules/Admin/Language/fa/Validation.php @@ -0,0 +1,17 @@ + + '{field} تصویر نبوده یا پنها و بلندایش کافی نیست.', + 'is_image_ratio' => + '{field} تصویر نبوده یا ابعادش درست نیست.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/fa/VideoClip.php b/modules/Admin/Language/fa/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/fa/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/fr-ca/AboutCastopod.php b/modules/Admin/Language/fr-ca/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/fr-ca/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Breadcrumb.php b/modules/Admin/Language/fr-ca/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/fr-ca/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/fr-ca/Charts.php b/modules/Admin/Language/fr-ca/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/fr-ca/Common.php b/modules/Admin/Language/fr-ca/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/fr-ca/Countries.php b/modules/Admin/Language/fr-ca/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/fr-ca/Dashboard.php b/modules/Admin/Language/fr-ca/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/fr-ca/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Episode.php b/modules/Admin/Language/fr-ca/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/fr-ca/EpisodeNavigation.php b/modules/Admin/Language/fr-ca/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/fr-ca/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/fr-ca/Fediverse.php b/modules/Admin/Language/fr-ca/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/fr-ca/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Home.php b/modules/Admin/Language/fr-ca/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/fr-ca/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/fr-ca/Install.php b/modules/Admin/Language/fr-ca/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/fr-ca/Navigation.php b/modules/Admin/Language/fr-ca/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Notifications.php b/modules/Admin/Language/fr-ca/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/fr-ca/Page.php b/modules/Admin/Language/fr-ca/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Pager.php b/modules/Admin/Language/fr-ca/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/fr-ca/Person.php b/modules/Admin/Language/fr-ca/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/fr-ca/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/fr-ca/Platforms.php b/modules/Admin/Language/fr-ca/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/fr-ca/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Podcast.php b/modules/Admin/Language/fr-ca/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/fr-ca/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/fr-ca/PodcastNavigation.php b/modules/Admin/Language/fr-ca/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/fr-ca/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/fr-ca/Settings.php b/modules/Admin/Language/fr-ca/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/fr-ca/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/fr-ca/Soundbite.php b/modules/Admin/Language/fr-ca/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/fr-ca/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/fr-ca/Validation.php b/modules/Admin/Language/fr-ca/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/fr-ca/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/fr-ca/VideoClip.php b/modules/Admin/Language/fr-ca/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/fr-ca/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/fr/AboutCastopod.php b/modules/Admin/Language/fr/AboutCastopod.php new file mode 100644 index 00000000..7cd9412b --- /dev/null +++ b/modules/Admin/Language/fr/AboutCastopod.php @@ -0,0 +1,22 @@ + 'À propos de Castopod', + 'host_name' => 'Nom d’hôte', + 'version' => 'Version de Castopod', + 'php_version' => 'Version de PHP', + 'os' => 'Système d\'exploitation', + 'languages' => 'Langues', + 'update_database' => 'Mettre à jour la base de données', + 'messages' => [ + 'databaseUpdateSuccess' => 'La base de données est à jour!', + ], +]; diff --git a/modules/Admin/Language/fr/Breadcrumb.php b/modules/Admin/Language/fr/Breadcrumb.php new file mode 100644 index 00000000..a4ac57a2 --- /dev/null +++ b/modules/Admin/Language/fr/Breadcrumb.php @@ -0,0 +1,57 @@ + 'Fil d’Ariane', + config('Admin') + ->gateway => 'Accueil', + 'podcasts' => 'podcasts', + 'episodes' => 'épisodes', + 'subscriptions' => 'abonnements', + 'contributors' => 'contributeurs', + 'pages' => 'pages', + 'settings' => 'paramètres', + 'theme' => 'thème', + 'about' => 'à propos', + 'add' => 'ajouter', + 'new' => 'créer', + 'edit' => 'modifier', + 'persons' => 'intervenants', + 'publish' => 'publier', + 'publish-edit' => 'modifier la publication', + 'publish-date-edit' => 'définir la date de publication', + 'unpublish' => 'dépublier', + 'delete' => 'supprimer', + 'remove' => 'retirer', + 'fediverse' => 'fédiverse', + 'blocked-actors' => 'acteurs bloqués', + 'blocked-domains' => 'domaines bloqués', + 'users' => 'utilisateurs', + 'my-account' => 'mon compte', + 'change-password' => 'changer le mot de passe', + 'imports' => 'imports', + 'sync-feeds' => 'synchroniser les flux', + 'platforms' => 'plateformes', + 'social' => 'réseaux sociaux', + 'funding' => 'financement', + 'monetization-other' => 'autres monétisations', + 'analytics' => 'mesures d’audience', + 'locations' => 'localisations', + 'webpages' => 'pages web', + 'unique-listeners' => 'auditeurs uniques', + 'players' => 'lecteurs', + 'listening-time' => 'durée d’écoute', + 'time-periods' => 'périodes', + 'soundbites' => 'extraits sonores', + 'video-clips' => 'extraits vidéo', + 'embed' => 'lecteur intégré', + 'notifications' => 'notifications', + 'suspend' => 'suspendre', +]; diff --git a/modules/Admin/Language/fr/Charts.php b/modules/Admin/Language/fr/Charts.php new file mode 100644 index 00000000..0c32f623 --- /dev/null +++ b/modules/Admin/Language/fr/Charts.php @@ -0,0 +1,41 @@ + 'Téléchargements d’épisodes par service (sur la dernière semaine)', + 'by_player_weekly' => 'Téléchargements d’épisodes par lecteur (sur la dernière semaine)', + 'by_player_yearly' => 'Téléchargements d’épisodes par lecteur (sur la dernière année)', + 'by_device_weekly' => 'Téléchargements d’épisodes par appareil (sur la dernière semaine)', + 'by_os_weekly' => 'Téléchargements d’épisodes par OS (sur la dernière semaine)', + 'podcast_by_region' => 'Téléchargements d’épisodes par région (sur la dernière semaine)', + 'unique_daily_listeners' => 'Auditeurs uniques quotidiens', + 'unique_monthly_listeners' => 'Auditeurs uniques mensuels', + 'by_browser' => 'Fréquentation des pages web par navigateur (sur la dernière semaine)', + 'podcast_by_day' => 'Téléchargements quotidiens d’épisodes', + 'podcast_by_month' => 'Téléchargements mensuels d’épisodes', + 'episode_by_day' => 'Téléchargements quotidiens de l’épisode (sur les 60 premiers jours)', + 'episode_by_month' => 'Téléchargements mensuels de l’épisode', + 'episodes_by_day' => + 'Téléchargements des 5 derniers épisodes (sur les 60 premiers jours)', + 'by_country_weekly' => 'Téléchargement d’épisodes par pays (sur la dernière semaine)', + 'by_country_yearly' => 'Téléchargement d’épisodes par pays (sur la dernière année)', + 'by_domain_weekly' => 'Fréquentation des pages web par origine (sur la dernière semaine)', + 'by_domain_yearly' => 'Fréquentation des pages web par origine (sur la dernière année)', + 'by_entry_page' => 'Fréquentation des pages web par page d’entrée (sur la dernière semaine)', + 'podcast_bots' => 'Robots (bots)', + 'daily_listening_time' => 'Durée quotidienne d’écoute cumulée', + 'monthly_listening_time' => 'Durée mensuelle d’écoute cumulée', + 'by_weekday' => 'Par jour de la semaine (sur les 60 derniers jours)', + 'by_hour' => 'Par heure de la journée (sur les 60 derniers jours)', + 'podcast_by_bandwidth' => 'Bande passante quotidienne consommée (en Mo)', + 'total_storage_by_month' => 'Stockage mensuel (en Mo)', + 'total_bandwidth_by_month' => 'Bande passante mensuelle utilisée (en Mo)', + 'total_bandwidth_by_month_limit' => 'Limité à {totalBandwidth} par mois', +]; diff --git a/modules/Admin/Language/fr/Common.php b/modules/Admin/Language/fr/Common.php new file mode 100644 index 00000000..d53347fb --- /dev/null +++ b/modules/Admin/Language/fr/Common.php @@ -0,0 +1,52 @@ + 'Oui', + 'no' => 'Non', + 'cancel' => 'Annuler', + 'optional' => 'Optionnel', + 'more' => 'Plus', + 'no_data' => 'Aucune donnée trouvée !', + 'close' => 'Fermer', + 'edit' => 'Modifier', + 'copy' => 'Copier', + 'copied' => 'Copié !', + 'home' => 'Accueil', + 'explicit' => 'Explicite', + 'powered_by' => 'Propulsé par {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} sur {pageCount}', + 'go_back' => 'Retour en arrière', + 'forms' => [ + 'editor' => [ + 'write' => 'Écrire', + 'preview' => 'Aperçu', + 'help' => 'Propulsé par markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Cliquez pour selectionner', + 'loadingText' => 'Chargement…', + 'noResultsText' => 'Aucun résultat trouvé', + 'noChoicesText' => 'Aucune sélection possible', + 'maxItemText' => 'Impossible de rajouter un élément', + ], + 'upload_file' => 'Téléversez un fichier', + 'remote_url' => 'URL distante', + 'save' => 'Sauvegarder', + ], + 'play_episode_button' => [ + 'play' => 'Lire', + 'playing' => 'En cours', + ], + 'size_limit' => 'Taille maximale : {0}.', + 'choose_interact' => 'Choisissez comment interagir', + 'view' => 'Voir', +]; diff --git a/modules/Admin/Language/fr/Countries.php b/modules/Admin/Language/fr/Countries.php new file mode 100644 index 00000000..475893b1 --- /dev/null +++ b/modules/Admin/Language/fr/Countries.php @@ -0,0 +1,264 @@ + 'Andorre', + 'AE' => 'Émirats Arabes Unis', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua-Et-Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albanie', + 'AM' => 'Arménie', + 'AO' => 'Angola', + 'AQ' => 'Antarctique', + 'AR' => 'Argentine', + 'AS' => 'Samoa Américaines', + 'AT' => 'Autriche', + 'AU' => 'Australie', + 'AW' => 'Aruba', + 'AX' => 'Åland, Îles', + 'AZ' => 'Azerbaïdjan', + 'BA' => 'Bosnie-Herzégovine', + 'BB' => 'Barbade', + 'BD' => 'Bangladesh', + 'BE' => 'Belgique', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgarie', + 'BH' => 'Bahreïn', + 'BI' => 'Burundi', + 'BJ' => 'Bénin', + 'BL' => 'Saint-Barthélemy', + 'BM' => 'Bermudes', + 'BN' => 'Brunéi Darussalam', + 'BO' => 'Bolivie, État Plurinational De', + 'BQ' => 'Bonaire, Saint-Eustache Et Saba', + 'BR' => 'Brésil', + 'BS' => 'Bahamas', + 'BT' => 'Bhoutan', + 'BV' => 'Bouvet, Île', + 'BW' => 'Botswana', + 'BY' => 'Bélarus', + 'BZ' => 'Bélize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling), Îles', + 'CD' => 'Congo, La République Démocratique Du', + 'CF' => 'Centrafricaine, République', + 'CG' => 'Congo', + 'CH' => 'Suisse', + 'CI' => "Côte D’ivoire", + 'CK' => 'Cook, Îles', + 'CL' => 'Chili', + 'CM' => 'Cameroun', + 'CN' => 'Chine', + 'CO' => 'Colombie', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cap-Vert', + 'CW' => 'Curaçao', + 'CX' => 'Christmas, Île', + 'CY' => 'Chypre', + 'CZ' => 'Tchéquie', + 'DE' => 'Allemagne', + 'DJ' => 'Djibouti', + 'DK' => 'Danemark', + 'DM' => 'Dominique', + 'DO' => 'République Dominicaine', + 'DZ' => 'Algérie', + 'EC' => 'Équateur', + 'EE' => 'Estonie', + 'EG' => 'Égypte', + 'EH' => 'Sahara Occidental', + 'ER' => 'Érythrée', + 'ES' => 'Espagne', + 'ET' => 'Éthiopie', + 'FI' => 'Finlande', + 'FJ' => 'Fidji', + 'FK' => 'Falkland, Îles (Malvinas)', + 'FM' => 'Micronésie, États Fédérés De', + 'FO' => 'Féroé, Îles', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'Royaume-Uni', + 'GD' => 'Grenade', + 'GE' => 'Géorgie', + 'GF' => 'Guyane Française', + 'GG' => 'Guernesey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenland', + 'GM' => 'Gambie', + 'GN' => 'Guinée', + 'GP' => 'Guadeloupe', + 'GQ' => 'Guinée Équatoriale', + 'GR' => 'Grèce', + 'GS' => 'Géorgie Du Sud Et Les Îles Sandwich Du Sud', + 'GT' => 'Guatémala', + 'GU' => 'Guam', + 'GW' => 'Guinée-Bissau', + 'GY' => 'Guyane', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Et Macdonald, Îles', + 'HN' => 'Honduras', + 'HR' => 'Croatie', + 'HT' => 'Haïti', + 'HU' => 'Hongrie', + 'ID' => 'Indonésie', + 'IE' => 'Irlande', + 'IL' => 'Israël', + 'IM' => 'Île De Man', + 'IN' => 'Inde', + 'IO' => 'Océan Indien, Territoire Britannique De L’', + 'IQ' => 'Irak', + 'IR' => 'Iran, République Islamique D’', + 'IS' => 'Islande', + 'IT' => 'Italie', + 'JE' => 'Jersey', + 'JM' => 'Jamaïque', + 'JO' => 'Jordanie', + 'JP' => 'Japon', + 'KE' => 'Kenya', + 'KG' => 'Kirghizistan', + 'KH' => 'Cambodge', + 'KI' => 'Kiribati', + 'KM' => 'Comores', + 'KN' => 'Saint-Kitts-Et-Nevis', + 'KP' => "Corée, République Populaire Démocratique De", + 'KR' => 'Corée, République De', + 'KW' => 'Koweït', + 'KY' => 'Caïmanes, Îles', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao, République Démocratique Populaire", + 'LB' => 'Liban', + 'LC' => 'Sainte-Lucie', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Libéria', + 'LS' => 'Lesotho', + 'LT' => 'Lituanie', + 'LU' => 'Luxembourg', + 'LV' => 'Lettonie', + 'LY' => 'Libye', + 'MA' => 'Maroc', + 'MC' => 'Monaco', + 'MD' => 'Moldavie', + 'ME' => 'Monténégro', + 'MF' => 'Saint-Martin (Partie Française)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall, Îles', + 'MK' => 'République De Macédoine', + 'ML' => 'Mali', + 'MM' => 'Birmanie', + 'MN' => 'Mongolie', + 'MO' => 'Macao', + 'MP' => 'Mariannes Du Nord, Îles', + 'MQ' => 'Martinique', + 'MR' => 'Mauritanie', + 'MS' => 'Montserrat', + 'MT' => 'Malte', + 'MU' => 'Maurice', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexique', + 'MY' => 'Malaisie', + 'MZ' => 'Mozambique', + 'N/A' => 'Non Applicable (IP locale…)', + 'NA' => 'Namibie', + 'NC' => 'Nouvelle-Calédonie', + 'NE' => 'Niger', + 'NF' => 'Norfolk, Île', + 'NG' => 'Nigéria', + 'NI' => 'Nicaragua', + 'NL' => 'Pays-Bas', + 'NO' => 'Norvège', + 'NP' => 'Népal', + 'NR' => 'Nauru', + 'NU' => 'Niué', + 'NZ' => 'Nouvelle-Zélande', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Pérou', + 'PF' => 'Polynésie Française', + 'PG' => 'Papouasie-Nouvelle-Guinée', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Pologne', + 'PM' => 'Saint-Pierre-Et-Miquelon', + 'PN' => 'Îles Pitcairn', + 'PR' => 'Porto Rico', + 'PS' => 'État De Palestine', + 'PT' => 'Portugal', + 'PW' => 'Palaos', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'La Réunion', + 'RO' => 'Roumanie', + 'RS' => 'Serbie', + 'RU' => 'Russie, Fédération De', + 'RW' => 'Rwanda', + 'SA' => 'Arabie Saoudite', + 'SB' => 'Salomon, Îles', + 'SC' => 'Seychelles', + 'SD' => 'Soudan', + 'SE' => 'Suède', + 'SG' => 'Singapour', + 'SH' => 'Sainte-Hélène, Ascension Et Tristan Da Cunha', + 'SI' => 'Slovénie', + 'SJ' => 'Svalbard Et Île Jan Mayen', + 'SK' => 'Slovaquie', + 'SL' => 'Sierra Leone', + 'SM' => 'Saint-Marin', + 'SN' => 'Sénégal', + 'SO' => 'Somalie', + 'SR' => 'Suriname', + 'SS' => 'Soudan Du Sud', + 'ST' => 'Sao Tomé-Et-Principe', + 'SV' => 'El Salvador', + 'SX' => 'Saint-Martin (Partie Néerlandaise)', + 'SY' => 'Syrienne, République Arabe', + 'SZ' => 'Eswatini', + 'TC' => 'Turks Et Caïques, Îles', + 'TD' => 'Tchad', + 'TF' => 'Terres Australes Françaises', + 'TG' => 'Togo', + 'TH' => 'Thaïlande', + 'TJ' => 'Tadjikistan', + 'TK' => 'Tokélaou', + 'TL' => 'Timor oriental', + 'TM' => 'Turkménistan', + 'TN' => 'Tunisie', + 'TO' => 'Tonga', + 'TR' => 'Turquie', + 'TT' => 'Trinité-Et-Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taïwan, Province De Chine', + 'TZ' => 'Tanzanie, République Unie De', + 'UA' => 'Ukraine', + 'UG' => 'Ouganda', + 'UM' => 'Îles Mineures Éloignées Des États-Unis', + 'US' => 'États-Unis', + 'UY' => 'Uruguay', + 'UZ' => 'Ouzbékistan', + 'VA' => 'Saint-Siège (État De La Cité Du Vatican)', + 'VC' => 'Saint-Vincent-Et-Les-Grenadines', + 'VE' => 'Venezuela, République Bolivarienne Du', + 'VG' => 'Îles Vierges Britanniques', + 'VI' => 'Îles Vierges Des États-Unis', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis-Et-Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yémen', + 'YT' => 'Mayotte', + 'ZA' => 'Afrique Du Sud', + 'ZM' => 'Zambie', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/fr/Dashboard.php b/modules/Admin/Language/fr/Dashboard.php new file mode 100644 index 00000000..010761fa --- /dev/null +++ b/modules/Admin/Language/fr/Dashboard.php @@ -0,0 +1,28 @@ + 'Tableau de bord', + 'welcome_message' => 'Bienvenue dans l\'espace d\'administration !', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Pas de podcast publié', + 'last_published' => 'Dernière publication le {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Épisodes', + 'not_found' => 'Aucun épisode publié', + 'last_published' => 'Dernière publication le {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Espace de stockage', + 'subtitle' => '{totalUploaded} sur {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/fr/Episode.php b/modules/Admin/Language/fr/Episode.php new file mode 100644 index 00000000..5b479992 --- /dev/null +++ b/modules/Admin/Language/fr/Episode.php @@ -0,0 +1,225 @@ + 'Saison {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Épisode {episodeNumber}', + 'number_abbr' => 'Ép. {episodeNumber}', + 'season_episode' => 'Saison {seasonNumber} épisode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}:E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# commentaire} + other {# commentaires} + }', + 'all_podcast_episodes' => 'Tous les épisodes du podcast', + 'back_to_podcast' => 'Revenir au podcast', + 'edit' => 'Modifier', + 'preview' => 'Prévisualisation', + 'publish' => 'Publier', + 'publish_edit' => 'Modifier la publication', + 'publish_date_edit' => 'Définir la date de publication', + 'unpublish' => 'Dépublier', + 'publish_error' => 'L’épisode est déjà publié.', + 'publish_edit_error' => 'L’épisode est déjà publié.', + 'publish_cancel_error' => 'L’épisode est déjà publié.', + 'publish_date_edit_error' => 'L\'épisode n\'a pas encore été publié, vous ne pouvez pas modifier sa date de publication.', + 'publish_date_edit_future_error' => 'La date de publication de l\'épisode ne peut être définie qu\'à une date antérieure! Si vous souhaitez la replanifier, dépubliez-la d\'abord.', + 'publish_date_edit_success' => 'La date de publication de l\'épisode a été mise à jour avec succès !', + 'unpublish_error' => 'L’épisode n’est pas publié.', + 'delete' => 'Supprimer', + 'go_to_page' => 'Voir', + 'create' => 'Ajouter un épisode', + 'publication_status' => [ + 'published' => 'Publié', + 'with_podcast' => 'Publié', + 'scheduled' => 'Planifié', + 'not_published' => 'Non publié', + ], + 'with_podcast_hint' => 'Publier en même temps que le podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Rechercher un épisode', + 'clear' => 'Effacer la recherche', + 'submit' => 'Recherche', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# épisode} + other {# épisodes} + }', + 'episode' => 'Épisode', + 'visibility' => 'Visibilité', + 'downloads' => 'Téléchargements', + 'comments' => 'Commentaires', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'L’épisode a été créé avec succès !', + 'editSuccess' => 'L’épisode a bien été mis à jour !', + 'publishSuccess' => '{publication_status, select, + published {Épisode publié avec succès !} + scheduled {La publication de l\'épisode est planifiée avec succès !} + with_podcast {Cet épisode sera publié en même temps que le podcast.} + other {Cet épisode n\'est pas publié.} + }', + 'publishCancelSuccess' => 'La publication de l’épisode a bien été annulée !', + 'unpublishBeforeDeleteTip' => 'Vous devez dépublier l\'épisode avant de le supprimer.', + 'scheduleDateError' => 'La date de planification doit être définie !', + 'deletePublishedEpisodeError' => 'Vous devez dépublier l\'épisode avant de le supprimer.', + 'deleteSuccess' => 'L\'épisode a bien été supprimé !', + 'deleteError' => 'Impossible de supprimer l\'épisode {type, select, + transcript {transcription} + chapters {chapitres} + image {couverture} + audio {audio} + other {média} + }.', + 'deleteFileError' => 'Impossible de supprimer le fichier {type, select, + transcript {de transcription} + chapters {de chapitres} + image {d’image de couverture} + audio {audio} + other {media} + } {file_key}. Vous pouvez le supprimer manuellement de votre disque.', + 'sameSlugError' => 'Il existe déjà un épisode avec le slug choisi.', + ], + 'form' => [ + 'file_size_error' => + 'Votre fichier est trop lourd ! La taille maximale est de {0}. Augmentez les valeurs de `memory_limit`, `upload_max_filesize` et `post_max_size` dans votre fichier de configuration php puis redémarrez votre serveur web pour téléverser votre fichier.', + 'audio_file' => 'Fichier audio', + 'audio_file_hint' => 'Sélectionnez un fichier audio .mp3 ou .m4a.', + 'info_section_title' => 'Informations épisode', + 'cover' => 'Image de couverture', + 'cover_hint' => + 'Si vous ne définissez pas d’image, celle du podcast sera utilisée à la place.', + 'cover_size_hint' => 'L’image doit être carrée et avoir au moins 1400px de largeur et de hauteur.', + 'title' => 'Titre', + 'title_hint' => + 'Doit contenir un titre d’épisode clair et concis. Ne précisez ici aucun numéro de saison ou d’épisode.', + 'permalink' => 'Lien permanent', + 'season_number' => 'Saison', + 'episode_number' => 'Épisode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Complet', + 'full_hint' => 'Épisode complet', + 'trailer' => 'Bande-annonce', + 'trailer_hint' => 'Extrait court, promotionnel du podcast', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Contenu supplémentaire pour le podcast (par exemple des informations sur les coulisses ou des interviews avec les acteurs) ou du contenu promotionnel croisé pour un autre podcast', + ], + 'premium_title' => 'Premium', + 'premium' => 'L\'épisode doit être accessible aux abonnés premium uniquement', + 'parental_advisory' => [ + 'label' => 'Avertissement parental', + 'hint' => 'L’épisode contient-il un contenu explicite ?', + 'undefined' => 'non défini', + 'clean' => 'Convenable', + 'explicit' => 'Explicite', + ], + 'show_notes_section_title' => 'Notes d’épisode (Show Notes)', + 'show_notes_section_subtitle' => + 'Jusque 4000 caractères, soyez clairs et concis. Les notes d’épisode aident les auditeurs potentiels à le trouver.', + 'description' => 'Description', + 'description_footer' => 'Pied de description', + 'description_footer_hint' => + 'Ce texte est ajouté à la fin de chaque description d’épisode, c’est un bon endroit pour placer vos liens sociaux par exemple.', + 'additional_files_section_title' => 'Fichiers additionels', + 'additional_files_section_subtitle' => + 'Ces fichiers pourront être utilisées par d’autres plate-formes pour procurer une meilleure expérience à vos auditeurs. Consulter le {podcastNamespaceLink} pour plus d’informations.', + 'location_section_title' => 'Localisation', + 'location_section_subtitle' => 'De quel lieu cet épisode parle-t-il ?', + 'location_name' => 'Nom ou adresse du lieu', + 'location_name_hint' => 'Ce lieu peut être réel ou fictif', + 'transcript' => 'Transcription (sous-titrage)', + 'transcript_hint' => 'Seuls les .srt ou .vtt sont autorisés.', + 'transcript_download' => 'Télécharger le transcript', + 'transcript_file' => 'Fichier de transcription (.srt ou .vtt)', + 'transcript_remote_url' => 'URL distante pour le fichier de transcription', + 'transcript_file_delete' => 'Supprimer le fichier de transcription', + 'chapters' => 'Chapitrage', + 'chapters_hint' => 'Le fichier doit être en format “JSON Chapters”.', + 'chapters_download' => 'Télécharger le chapitrage', + 'chapters_file' => 'Fichier de chapitrage', + 'chapters_remote_url' => 'URL distante pour le fichier de chapitrage', + 'chapters_file_delete' => 'Supprimer le fichier de chapitrage', + 'advanced_section_title' => 'Paramètres avancés', + 'advanced_section_subtitle' => + 'Si vous avez besoin d’une balise que Castopod ne couvre pas, définissez-la ici.', + 'custom_rss' => 'Balises RSS personnalisées pour l’épisode', + 'custom_rss_hint' => 'Ceci sera injecté dans la balise ❬item❭.', + 'block' => 'L\'épisode doit être masqué dans les catalogues publics', + 'block_hint' => + 'L\'épisode montre ou masque le statut: activer ceci empêche l\'épisode d\'apparaître dans les Podcasts Apple, Google Podcasts, et toutes les applications tierces qui tirent vers ces répertoires. (non garanti)', + 'submit_create' => 'Créer l’épisode', + 'submit_edit' => 'Enregistrer l’épisode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Retour au tableau de bord de l’épisode', + 'post' => 'Votre message de publication', + 'post_hint' => + "Écrivez un message pour annoncer la publication de votre épisode. Le message sera diffusé à toutes les personnes qui vous suivent dans le fédiverse et mis en évidence sur la page d’accueil de votre podcast.", + 'message_placeholder' => 'Entrez votre message…', + 'publication_date' => 'Date de publication', + 'publication_method' => [ + 'now' => 'Maintenant', + 'schedule' => 'Planifier', + 'with_podcast' => 'Publier à côté du podcast', + ], + 'scheduled_publication_date' => 'Date de publication programmée', + 'scheduled_publication_date_clear' => 'Effacer la date de publication', + 'scheduled_publication_date_hint' => + 'Vous pouvez planifier la sortie de l’épisode en saisissant une date de publication future. Ce champ doit être au format YYYY-MM-DD HH:mm', + 'submit' => 'Publier', + 'submit_edit' => 'Modifier la publication', + 'cancel_publication' => 'Annuler la publication', + 'message_warning' => 'Vous n’avez pas saisi de message pour l’annonce de votre épisode !', + 'message_warning_hint' => 'Ajouter un message augmente l’engagement social, menant à une meilleure visibilité pour votre épisode.', + 'message_warning_submit' => 'Publier quand même', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Date de la prochaine publication', + 'new_publication_date_hint' => 'Doit être défini à une date antérieure.', + 'submit' => 'Définir la date de publication', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Dépublier l'épisode supprimera tous les commentaires et messages qui lui sont associés et le supprimera du flux RSS du podcast.", + 'understand' => 'Je comprends, je veux dépublier l’épisode', + 'submit' => 'Dépublier', + ], + 'delete_form' => [ + 'disclaimer' => + "La suppression de l'épisode supprimera tous les fichiers multimédia, les commentaires, les clips vidéo et les parties sonores qui y sont associées.", + 'understand' => 'Je comprends, je veux supprimer l’épisode', + 'submit' => 'Supprimer', + ], + 'embed' => [ + 'title' => 'Lecteur intégré', + 'label' => + 'Sélectionnez une couleur de thème, copiez le code dans le presse-papier, puis collez-le sur votre site internet.', + 'clipboard_iframe' => 'Copier le lecteur dans le presse papier', + 'clipboard_url' => 'Copier l’adresse dans le presse papier', + 'dark' => 'Sombre', + 'dark-transparent' => 'Sombre transparent', + 'light' => 'Clair', + 'light-transparent' => 'Clair transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'mode brouillon', + 'text' => '{publication_status, select, + published {Cet épisode n’est pas encore publié.} + scheduled {Cet épisode est programmé pour le {publication_date}.} + with_podcast {Cet épisode va être publié au même moment que le podcast.} + other {Cet épisode n’est pas encore publié.} + }', + 'preview' => 'Prévisualisation', + ], +]; diff --git a/modules/Admin/Language/fr/EpisodeNavigation.php b/modules/Admin/Language/fr/EpisodeNavigation.php new file mode 100644 index 00000000..a365a3aa --- /dev/null +++ b/modules/Admin/Language/fr/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Aller à la page de l’épisode', + 'dashboard' => 'Tableau de bord de l’épisode', + 'episode-view' => 'Accueil', + 'episode-edit' => 'Modifier l’épisode', + 'episode-persons-manage' => 'Gestion des intervenants', + 'embed-add' => 'Lecteur intégré', + 'clips' => 'Extraits', + 'video-clips-list' => 'Extraits video', + 'video-clips-create' => 'Nouvel extrait video', + 'soundbites-list' => 'Extraits sonores', + 'soundbites-create' => 'Nouvel extrait sonore', +]; diff --git a/modules/Admin/Language/fr/Fediverse.php b/modules/Admin/Language/fr/Fediverse.php new file mode 100644 index 00000000..95d3a964 --- /dev/null +++ b/modules/Admin/Language/fr/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'L’utilisateur n’a pu être trouvé !', + 'blockActorSuccess' => '{actor} a été bloqué !', + 'unblockActorSuccess' => 'L’utilisateur a été débloqué !', + 'blockDomainSuccess' => '{domain} a été bloqué !', + 'unblockDomainSuccess' => '{domain} a été débloqué !', + ], + 'blocked_actors' => 'Utilisateurs bloqués', + 'blocked_domains' => 'Domaines bloqués', + 'block_lists_form' => [ + 'handle' => 'Identifiant', + 'handle_hint' => 'Saisissez l’utilisateur @nom@domaine.', + 'domain' => 'Nom de domaine', + 'submit' => 'Bloquer !', + ], + 'list' => [ + 'actor' => 'Utilisateur', + 'domain' => 'Nom de domaine', + 'unblock' => 'Débloquer', + ], +]; diff --git a/modules/Admin/Language/fr/Home.php b/modules/Admin/Language/fr/Home.php new file mode 100644 index 00000000..0ec83396 --- /dev/null +++ b/modules/Admin/Language/fr/Home.php @@ -0,0 +1,14 @@ + 'Tous les podcasts', + 'no_podcast' => 'Aucun podcast trouvé', +]; diff --git a/modules/Admin/Language/fr/Install.php b/modules/Admin/Language/fr/Install.php new file mode 100644 index 00000000..f7c26785 --- /dev/null +++ b/modules/Admin/Language/fr/Install.php @@ -0,0 +1,61 @@ + 'Configuration manuelle', + 'manual_config_subtitle' => + 'Créez un fichier `.env` qui contient tous vos paramètres puis rafraichissez la page pour continuer l’installation.', + 'form' => [ + 'instance_config' => 'Paramètres de l’instance', + 'hostname' => 'Nom d’hôte', + 'media_base_url' => 'Adresse racine des médias', + 'media_base_url_hint' => + 'Si vous utilisez un CDN et/ou un service de mesure d’audience externe, vous pouvez les définir ici.', + 'admin_gateway' => 'Adresse d’administration', + 'admin_gateway_hint' => + 'Le chemin pour accéder à l’administration (par exemple https://example.com/cp-admin). Il est défini par défaut à cp-admin, nous vous recommandons de le changer par mesure de sécurité.', + 'auth_gateway' => 'Adresse d’authentification', + 'auth_gateway_hint' => + 'Le chemin des pages d’authentication (par exemple https://example.fr/cp-auth). Il est défini par défaut à cp-auth, nous vous recommandons de le changer par mesure de sécurité.', + 'database_config' => 'Paramètres de base de données', + 'database_config_hint' => + 'Castopod doit se connecter à votre base de données MySQL (ou MariaDB). Si vous ne disposez pas de ces informations, merci de contacter l’administrateur du serveur.', + 'db_hostname' => 'Nom d’hôte (ou IP) de la base de données', + 'db_name' => 'Nom de la base de données', + 'db_username' => 'Utilisateur de base de données', + 'db_password' => 'Mot de passe de base de données', + 'db_prefix' => 'Préfixe des tables', + 'db_prefix_hint' => + "Le préfixe des noms de tables de Castopod, laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.", + 'cache_config' => 'Paramètres de cache', + 'cache_config_hint' => + 'Sélectionnez votre gestionnaire de cache préféré. Laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.', + 'cache_handler' => 'Gestionnaire de cache', + 'cacheHandlerOptions' => [ + 'file' => 'Fichiers', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Suivant', + 'submit' => 'Terminer l’installation', + 'create_superadmin' => 'Créer un compte super-utilisateur', + 'email' => 'E-mail', + 'username' => 'Identifiant', + 'password' => 'Mot de passe', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Le compte super-utilisateur a bien été créé. Connectez-vous et commencez à podcaster !', + 'databaseConnectError' => + 'Castopod n’a pas pu se connecter à la base de données. Modifiez les paramètres de base de données et essayez à nouveau.', + 'writeError' => + "Impossible de créer/écrire le fichier `.env`. Créez manuellement un fichier `.env` en copiant le modèle `.env.example` fourni avec Castopod.", + ], +]; diff --git a/modules/Admin/Language/fr/Navigation.php b/modules/Admin/Language/fr/Navigation.php new file mode 100644 index 00000000..b3fd182b --- /dev/null +++ b/modules/Admin/Language/fr/Navigation.php @@ -0,0 +1,44 @@ + 'Afficher ou cacher la barre latérale', + 'go_to_website' => 'Aller au site', + 'go_to_admin' => 'Aller à l’admin', + 'not-authorized' => 'Non autorisé', + 'dashboard' => 'Tableau de bord', + 'admin' => 'Accueil', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Tous les podcasts', + 'podcast-create' => 'Créer un podcast', + 'all-podcast-imports' => 'Tous les imports de Podcast', + 'podcast-imports-add' => 'Importer un podcast', + 'persons' => 'Intervenants', + 'person-list' => 'Tous les intervenants', + 'person-create' => 'Créer un intervenant', + 'fediverse' => 'Fédiverse', + 'fediverse-blocked-actors' => 'Utilisateurs bloqués', + 'fediverse-blocked-domains' => 'Domaines bloqués', + 'users' => 'Utilisateurs', + 'user-list' => 'Tous les utilisateurs', + 'user-create' => 'Créer un utilisateur', + 'pages' => 'Pages', + 'page-list' => 'Toutes les pages', + 'page-create' => 'Créer une page', + 'settings' => 'Paramètres', + 'settings-general' => 'Général', + 'settings-theme' => 'Thème', + 'admin-about' => 'À propos', + 'account' => [ + 'my-account' => 'Mon compte', + 'change-password' => 'Modifier le mot de passe', + 'logout' => 'Déconnexion', + ], +]; diff --git a/modules/Admin/Language/fr/Notifications.php b/modules/Admin/Language/fr/Notifications.php new file mode 100644 index 00000000..003b2bbb --- /dev/null +++ b/modules/Admin/Language/fr/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} a répondu à votre message', + 'favourite' => '{actor_username} a mis en favori votre message', + 'reblog' => '{actor_username} à partagé votre message', + 'follow' => '{actor_username} commencé à te suivre', + 'no_notifications' => 'Aucune notification', + 'mark_all_as_read' => 'Tout marquer comme lu', +]; diff --git a/modules/Admin/Language/fr/Page.php b/modules/Admin/Language/fr/Page.php new file mode 100644 index 00000000..32a032ff --- /dev/null +++ b/modules/Admin/Language/fr/Page.php @@ -0,0 +1,30 @@ + 'Retour à l’accueil', + 'page' => 'Page', + 'all_pages' => 'Toutes les pages', + 'create' => 'Créer une page', + 'go_to_page' => 'Aller à la page', + 'edit' => 'Modifier la page', + 'delete' => 'Supprimer la page', + 'form' => [ + 'title' => 'Titre', + 'permalink' => 'Lien permanent', + 'content' => 'Contenu', + 'submit_create' => 'Créer la page', + 'submit_edit' => 'Enregistrer', + ], + 'messages' => [ + 'createSuccess' => 'La page “{pageTitle}” a été créée avec succès !', + 'editSuccess' => 'La page a bien été mise à jour !', + ], +]; diff --git a/modules/Admin/Language/fr/Pager.php b/modules/Admin/Language/fr/Pager.php new file mode 100644 index 00000000..8a5dd2e2 --- /dev/null +++ b/modules/Admin/Language/fr/Pager.php @@ -0,0 +1,21 @@ + 'Navigation', + 'first' => 'Première', + 'previous' => 'Précédent', + 'next' => 'Suivant', + 'last' => 'Dernière', + 'older' => 'Plus ancien', + 'newer' => 'Plus récent', + 'invalidTemplate' => '{0} n’est pas un modèle valide.', + 'invalidPaginationGroup' => '{0} n’est pas un groupe valide.', +]; diff --git a/modules/Admin/Language/fr/Person.php b/modules/Admin/Language/fr/Person.php new file mode 100644 index 00000000..afd6d28f --- /dev/null +++ b/modules/Admin/Language/fr/Person.php @@ -0,0 +1,65 @@ + 'Intervenants', + 'all_persons' => 'Tous les intervenants', + 'no_person' => 'Aucun intervenant trouvé !', + 'create' => 'Créer un intervenant', + 'view' => 'Voir l’intervenant', + 'edit' => 'Modifier l’intervenant', + 'delete' => 'Supprimer l’intervenant', + 'messages' => [ + 'createSuccess' => 'L’intervenant a été créé avec succès !', + 'editSuccess' => 'L’intervenant a bien été mis à jour !', + 'deleteSuccess' => 'L’intervenant a bien été retiré !', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'L\'avatar doit être carré et au moins 400px de largeur et de hauteur.', + 'full_name' => 'Nom complet', + 'full_name_hint' => 'Le nom complet ou le pseudonyme de l’intervenant', + 'unique_name' => 'Nom unique', + 'unique_name_hint' => 'Utilisé pour les URLs', + 'information_url' => 'Adresse d’information', + 'information_url_hint' => + 'URL pointant vers des informations relatives à l’intervenant, telle qu’une page personnelle ou une page de profil sur une plateforme tierce.', + 'submit_create' => 'Créer l’intervenant', + 'submit_edit' => 'Enregistrer l’intervenant', + ], + 'podcast_form' => [ + 'title' => 'Gérer les intervenants', + 'add_section_title' => 'Ajouter des intervenants à ce podcast', + 'add_section_subtitle' => 'Vous pouvez sélectionner plusieurs intervenants et rôles.', + 'persons' => 'Intervenants', + 'persons_hint' => + 'Vous pouvez selectionner un ou plusieurs intervenants ayant les mêmes rôles. Les intervenants doivent avoir été préalablement créés.', + 'roles' => 'Groupes et rôles', + 'roles_hint' => + 'Vous pouvez sélectionner aucun, un ou plusieurs groupes et rôles par intervenant.', + 'submit_add' => 'Ajouter un/des intervenant(s)', + 'remove' => 'Retirer', + ], + 'episode_form' => [ + 'title' => 'Gérer les intervenants', + 'add_section_title' => 'Ajouter des intervenants à cet épisode', + 'add_section_subtitle' => 'Vous pouvez sélectionner plusieurs intervenants et rôles.', + 'persons' => 'Intervenants', + 'persons_hint' => + 'Vous pouvez selectionner un ou plusieurs intervenants ayant les mêmes rôles. Les intervenants doivent avoir été préalablement créés.', + 'roles' => 'Groupes et rôles', + 'roles_hint' => + 'Vous pouvez sélectionner aucun, un ou plusieurs groupes et rôles par intervenant.', + 'submit_add' => 'Ajouter un/des intervenant(s)', + 'remove' => 'Retirer', + ], + 'credits' => 'Crédits', +]; diff --git a/modules/Admin/Language/fr/Platforms.php b/modules/Admin/Language/fr/Platforms.php new file mode 100644 index 00000000..3e2f9eee --- /dev/null +++ b/modules/Admin/Language/fr/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Plateformes de Podcasting', + 'social' => 'Réseaux sociaux', + 'funding' => 'Liens de financement', + ], + 'website' => 'Site web', + 'home_url' => 'Aller au site {platformName}', + 'register' => 'S\'inscrire', + 'submit_url' => 'Soumettez votre podcast sur {platformName}', + 'your_link' => 'Votre lien', + 'your_id' => [ + 'podcasting' => 'Votre identifiant', + 'social' => 'Votre identifiant', + 'funding' => 'Votre CTA', + ], + 'your_cta' => 'Votre appel à l\'action', + 'visible' => 'Afficher sur la page d’accueil du podcast ?', + 'on_embed' => 'Afficher sur le lecteur intégré ?', + 'remove' => 'Supprimer {platformName}', + 'submit' => 'Enregistrer', + 'messages' => [ + 'updateSuccess' => 'Les liens ont été enregistrés avec succès !', + 'removeLinkSuccess' => 'Le lien a été supprimé.', + 'removeLinkError' => + 'Le lien n’a pas pu être supprimé. Merci d’essayer à nouveau.', + ], + 'description' => [ + 'podcasting' => 'L’identifiant du podcast sur cette plate-forme', + 'social' => 'L’identifiant du compte du podcast sur cette plate-forme', + 'funding' => 'Message d’incitation à l’action', + ], +]; diff --git a/modules/Admin/Language/fr/Podcast.php b/modules/Admin/Language/fr/Podcast.php new file mode 100644 index 00000000..feadf6d3 --- /dev/null +++ b/modules/Admin/Language/fr/Podcast.php @@ -0,0 +1,330 @@ + 'Tous les podcasts', + 'no_podcast' => 'Aucun podcast trouvé !', + 'create' => 'Créer un podcast', + 'import' => 'Importer un podcast', + 'all_imports' => 'Imports de podcasts', + 'new_episode' => 'Créer un épisode', + 'view' => 'Voir le podcast', + 'edit' => 'Modifier le podcast', + 'publish' => 'Publier le podcast', + 'publish_edit' => 'Modifier la publication', + 'delete' => 'Supprimer le podcast', + 'see_episodes' => 'Voir les épisodes', + 'see_contributors' => 'Voir les contributeurs', + 'monetization_other' => 'Autres monétisations', + 'go_to_page' => 'Aller à la page', + 'latest_episodes' => 'Derniers épisodes', + 'see_all_episodes' => 'Voir tous les épisodes', + 'draft' => 'Brouillon', + 'messages' => [ + 'createSuccess' => 'Le podcast a été créé avec succès !', + 'editSuccess' => 'Le podcast a bien été mis à jour !', + 'importSuccess' => 'Le podcast a été importé avec succès !', + 'deleteSuccess' => 'Podcast @{podcast_handle} a été supprimé avec succès !', + 'deletePodcastMediaError' => 'Impossible de supprimer le podcast {type, select, + cover {couverture} + banner {bannière} + other {média} + }.', + 'deleteEpisodeMediaError' => 'Impossible de supprimer l\'épisode de podcast {episode_slug} {type, select, + transcript {transcription} + chapters {chapitres} + image {couverture} + audio {audio} + other {média} + }.', + 'deletePodcastMediaFolderError' => 'Impossible de supprimer le dossier de podcast {folder_path}. Vous pouvez le supprimer manuellement de votre disque.', + 'podcastFeedUpdateSuccess' => 'Mise à jour réussie : {number_of_new_episodes, plural, + one {# épisode a été} + other {# épisodes ont été} + } ajoutés au podcast!', + 'podcastFeedUpToDate' => 'Le podcast est déjà à jour.', + 'publishError' => 'Ce podcast est soit déjà publié, soit programmé pour publication.', + 'publishEditError' => 'Ce podcast n\'est pas programmé pour publication.', + 'publishCancelSuccess' => 'Publication de Podcast annulée avec succès !', + 'scheduleDateError' => 'La date de planification doit être définie !', + ], + 'form' => [ + 'identity_section_title' => 'Informations sur le Podcast', + 'identity_section_subtitle' => 'Ces champs vous permettent de vous faire remarquer.', + 'fediverse_section_title' => 'Identité dans le Fédivers', + + 'cover' => 'Couverture du podcast', + 'cover_size_hint' => 'La couverture du podcast doit être carrée, avec au minimum 1400px de largeur et de hauteur.', + 'banner' => 'Bannière du podcast', + 'banner_size_hint' => 'La bannière doit être au format 3/1, avec au minimum 1500px de largeur.', + 'banner_delete' => 'Supprimer la bannière du podcast', + 'title' => 'Titre', + 'handle' => 'Identifiant', + 'handle_hint' => + 'Utilisé pour identifier le podcast. Les majuscules, les minuscules, les chiffres et le caractère souligné « _ » sont acceptés.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Épisodique', + 'episodic_hint' => 'Si les épisodes sont destinés à être consommés sans ordre spécifique. Les épisodes les plus récents seront présentés en premier.', + 'serial' => 'Série', + 'serial_hint' => 'Si les épisodes sont destinés à êtres lus dans un ordre séquentiel. Les épisodes seront présentés dans l’ordre de numérotation.', + ], + 'medium' => [ + 'label' => 'Médium', + 'hint' => 'Médium tel que représenté par la balise podcast:medium dans le flux RSS. Changer ceci peut changer la façon dont les lecteurs présentent votre flux.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Décrit un flux pour une émission de podcast.', + 'music' => 'Musique', + 'music_hint' => 'Un flux de musique organisé en un "album", chaque élément étant une chanson de l\'album.', + 'audiobook' => 'Livre audio', + 'audiobook_hint' => 'Types d\'audio spécifiques avec un élément par flux, ou lorsque des éléments représentent des chapitres dans le livre.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'Ces champs auront un impact sur votre audience et votre concurrence.', + 'language' => 'Langue', + 'category' => 'Catégorie', + 'category_placeholder' => 'Sélectionner une catégorie…', + 'other_categories' => 'Autres catégories', + 'parental_advisory' => [ + 'label' => 'Avertissement parental', + 'hint' => 'Contient-il un contenu explicite ?', + 'undefined' => 'non défini', + 'clean' => 'Convenable', + 'explicit' => 'Explicite', + ], + 'author_section_title' => 'Auteur / Autrice', + 'author_section_subtitle' => 'Qui gère le podcast ?', + 'owner_name' => 'Nom du/de la propriétaire', + 'owner_name_hint' => + 'Pour usage administratif uniquement. Visible dans le flux RSS public.', + 'owner_email' => 'E-mail du/de la propriétaire', + 'owner_email_hint' => + 'Utilisé par la plupart des plateformes pour vérifier la propriété du podcast. Visible dans le flux RSS public.', + 'is_owner_email_removed_from_feed' => 'Retirer l\'email du propriétaire du flux RSS publique', + 'is_owner_email_removed_from_feed_hint' => 'Il se peut que vous deviez temporairement exposer l’email pour qu\'un index puisse valider la propriété de votre podcast.', + 'publisher' => 'Éditeur / Éditrice', + 'publisher_hint' => + 'Le groupe responsable de la création du podcast. Fait souvent référence à la société mère ou au réseau d’un podcast. Ce champ est parfois appelé « Auteur ».', + 'copyright' => 'Droit d’auteur', + 'location_section_title' => 'Localisation', + 'location_section_subtitle' => 'De quel lieu ce podcast parle-t-il ?', + 'location_name' => 'Nom ou adresse du lieu', + 'location_name_hint' => 'Ce lieu peut être réel ou fictif', + 'monetization_section_title' => 'Monétisation', + 'monetization_section_subtitle' => + 'Gagnez de l’argent grâce à votre audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Les épisodes doivent être définis comme premium par défaut', + 'premium_by_default_hint' => 'Les épisodes de Podcast seront marqués comme premium par défaut. Vous pouvez toujours choisir de définir certains épisodes, bandes-annonces ou bonus comme publics.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visitez votre tableau de bord OP3 (lien externe)', + 'op3_hint' => 'Valorisez vos données d\'analyse avec OP3, un service d\'analyse tiers open source et de confiance. Partagez, validez et comparez vos données analytiques avec l\'écosystème de podcasting ouvert.', + 'op3_enable' => 'Activer le service d\'analyse OP3', + 'op3_enable_hint' => 'Pour des raisons de sécurité, les données d\'analyse des épisodes premium ne seront pas partagées avec OP3.', + 'payment_pointer' => 'Adresse de paiement (Payment Pointer) pour Web Monetization', + 'payment_pointer_hint' => + 'L’adresse où vous recevrez de l’argent grâce à Web Monetization', + 'advanced_section_title' => 'Paramètres avancés', + 'advanced_section_subtitle' => + 'Si vous avez besoin d’une balise que nous n’avons pas couverte, définissez-la ici.', + 'custom_rss' => 'Balises RSS personnalisées pour le podcast', + 'custom_rss_hint' => 'Ceci sera injecté dans la balise ❬channel❭.', + 'verify_txt' => 'Vérification de propriété TXT', + 'verify_txt_hint' => 'Plutôt que de se fier au courrier électronique, certains services tiers peuvent confirmer la propriété de votre podcast en vous demandant d\'intégrer un texte de vérification dans votre flux.', + 'verify_txt_helper' => 'Ce texte est injecté dans une balise .', + 'new_feed_url' => 'URL du nouveau flux', + 'new_feed_url_hint' => 'Utilisez ce champ lorsque vous déplacez ce podcast vers un autre domaine ou que vous changez d’hébergeur. Par défaut, ce champ est rempli avec l’URL du flux actuel si le podcast est importé.', + 'old_feed_url' => 'URL de l\'ancien flux', + 'partnership' => 'Partenariat', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL lien', + 'partner_image_url' => 'URL image', + 'partner_id_hint' => 'Votre identifiant personnel partenaire', + 'partner_link_url_hint' => 'L’adresse générique des liens partenaire', + 'partner_image_url_hint' => 'L’adresse générique des images partenaire', + 'block' => 'L\'épisode doit être masqué dans les catalogues publics', + 'block_hint' => + 'Le statut d\'affichage ou de masquage du podcast : activer cette option empêche l\'intégralité du podcast d\'apparaître dans les podcasts Apple, Google Podcasts et toutes les applications tierces qui extraient des émissions de ces répertoires. (Pas garantie)', + 'complete' => 'Le podcast n’aura plus de nouveaux épisodes.', + 'lock' => 'Empêcher la copie du podcast', + 'lock_hint' => + 'Le but est d’indiquer aux autres plates-formes de podcast si elles sont autorisées à importer ce flux. La valeur « oui » signifie que toute tentative d’importation de ce flux dans une nouvelle plateforme doit être rejetée.', + 'submit_create' => 'Créer le podcast', + 'submit_edit' => 'Enregistrer le podcast', + ], + 'category_options' => [ + 'uncategorized' => 'non catégorisé', + 'arts' => 'Arts', + 'business' => 'Entreprise', + 'comedy' => 'Comédie', + 'education' => 'Éducation', + 'fiction' => 'Fiction', + 'government' => 'Gouvernement', + 'health_and_fitness' => 'Santé et remise en forme', + 'history' => 'Histoire', + 'kids_and_family' => 'Enfants et famille', + 'leisure' => 'Loisirs', + 'music' => 'Musique', + 'news' => 'Actualités', + 'religion_and_spirituality' => 'Religion et spiritualité', + 'science' => 'Science', + 'society_and_culture' => 'Société et Culture', + 'sports' => 'Sports', + 'technology' => 'Technologie', + 'true_crime' => 'Documentaire criminel', + 'tv_and_film' => 'Télévision et films', + 'books' => 'Livres', + 'design' => 'Design', + 'fashion_and_beauty' => 'Mode et beauté', + 'food' => 'Nourriture', + 'performing_arts' => 'Arts du spectacle', + 'visual_arts' => 'Arts visuels', + 'careers' => 'Carrières', + 'entrepreneurship' => 'Entrepreneuriat', + 'investing' => 'Investissement', + 'management' => 'Gestion', + 'marketing' => 'Marketing', + 'non_profit' => 'À but non lucratif', + 'comedy_interviews' => 'Entretiens comiques', + 'improv' => 'Improvisation', + 'stand_up' => 'Stand up', + 'courses' => 'Cours', + 'how_to' => 'Tutoriels', + 'language_learning' => 'Apprentissage des langues', + 'self_improvement' => 'Développement personnel', + 'comedy_fiction' => 'Comédie Fiction', + 'drama' => 'Drame', + 'science_fiction' => 'Science-fiction', + 'alternative_health' => 'Santé alternative', + 'fitness' => 'Remise en forme', + 'medicine' => 'Médecine', + 'mental_health' => 'Santé mentale', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexualité', + 'education_for_kids' => 'Éducation pour les enfants', + 'parenting' => 'Parentalité', + 'pets_and_animals' => 'Animaux de compagnie et animaux', + 'stories_for_kids' => 'Histoires pour enfants', + 'animation_and_manga' => 'Animation et Manga', + 'automotive' => 'Automobile', + 'aviation' => 'Aviation', + 'crafts' => 'Artisanat', + 'games' => 'Jeux', + 'hobbies' => 'Loisirs', + 'home_and_garden' => 'Maison et jardin', + 'video_games' => 'Jeux vidéo', + 'music_commentary' => 'Commentaire musical', + 'music_history' => 'Histoire de la musique', + 'music_interviews' => 'Entretiens musicaux', + 'business_news' => 'Actualités économiques', + 'daily_news' => 'Actualités quotidiennes', + 'entertainment_news' => 'Actualités du divertissement', + 'news_commentary' => 'Commentaire d’actualité', + 'politics' => 'Politique', + 'sports_news' => 'Actualités sportives', + 'tech_news' => 'Actualités techniques', + 'buddhism' => 'Bouddhisme', + 'christianity' => 'Christianisme', + 'hinduism' => 'Hindouisme', + 'islam' => 'Islam', + 'judaism' => 'Judaïsme', + 'religion' => 'Religion', + 'spirituality' => 'Spiritualité', + 'astronomy' => 'Astronomie', + 'chemistry' => 'Chimie', + 'earth_sciences' => 'Sciences de la Terre', + 'life_sciences' => 'Sciences de la vie', + 'mathematics' => 'Mathématiques', + 'natural_sciences' => 'Sciences naturelles', + 'nature' => 'Nature', + 'physics' => 'Physique', + 'social_sciences' => 'Sciences sociales', + 'documentary' => 'Documentaire', + 'personal_journals' => 'Journaux personnels', + 'philosophy' => 'Philosophie', + 'places_and_travel' => 'Lieux et voyages', + 'relationships' => 'Relations', + 'baseball' => 'Baseball', + 'basketball' => 'Basket-ball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Sports fantastiques', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Course', + 'soccer' => 'Football', + 'swimming' => 'Natation', + 'tennis' => 'Tennis', + 'volleyball' => 'Volley-ball', + 'wilderness' => 'Naturalité', + 'wrestling' => 'Lutte', + 'after_shows' => 'Après spectacle', + 'film_history' => 'Histoire du cinéma', + 'film_interviews' => 'Entretiens de films', + 'film_reviews' => 'Critiques de films', + 'tv_reviews' => 'Critiques TV', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Retour au tableau de bord des podcasts', + 'post' => 'Votre message de publication', + 'post_hint' => + "Écrivez un message pour annoncer la publication de votre podcast. Le message sera affiché sur la page d'accueil de votre podcast.", + 'message_placeholder' => 'Rédiger votre message…', + 'submit' => 'Publier', + 'publication_date' => 'Date de publication', + 'publication_method' => [ + 'now' => 'Maintenant', + 'schedule' => 'Planifier', + ], + 'scheduled_publication_date' => 'Date de publication programmée', + 'scheduled_publication_date_hint' => + 'Vous pouvez planifier la sortie de l’épisode en saisissant une date de publication. Ce champ doit être au format YYYY-MM-DD HH:mm', + 'submit_edit' => 'Modifier la publication', + 'cancel_publication' => 'Annuler la publication', + 'message_warning' => 'Vous n’avez pas saisi de message pour l’annonce de votre épisode !', + 'message_warning_hint' => 'Avoir un message augmente l\'engagement social, résultant en une meilleure visibilité pour votre podcast.', + 'message_warning_submit' => 'Publier quand même', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'Mode brouillon', + 'not_published' => 'Ce podcast n\'est pas encore publié.', + 'scheduled' => 'Ce podcast est programmé pour être publié le {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "La suppression du podcast supprimera tous les épisodes, fichiers multimédia, messages et statistiques qui y sont associées. Cette action est irréversible, vous ne pourrez plus les récupérer par la suite.", + 'understand' => 'Je comprends, je souhaite que le podcast soit définitivement supprimé', + 'submit' => 'Supprimer', + ], + 'by' => 'Par {publisher}', + 'season' => 'Saison {seasonNumber}', + 'list_of_episodes_year' => 'Épisodes de {year} ({episodeCount})', + 'list_of_episodes_season' => + 'Épisodes de la saison {seasonNumber} ({episodeCount})', + 'no_episode' => 'Aucun épisode trouvé !', + 'follow' => 'Suivre', + 'followers' => '{numberOfFollowers, plural, + one {# abonné·e} + other {# abonné·e·s} + }', + 'posts' => '{numberOfPosts, plural, + one {# publication} + other {# publications} + }', + 'activity' => 'Activité', + 'episodes' => 'Épisodes', + 'sponsor' => 'Soutenez-nous', + 'funding_links' => 'Liens de financement pour {podcastTitle}', + 'find_on' => 'Trouvez {podcastTitle} sur', + 'listen_on' => 'Écoutez sur', +]; diff --git a/modules/Admin/Language/fr/PodcastNavigation.php b/modules/Admin/Language/fr/PodcastNavigation.php new file mode 100644 index 00000000..f02631d4 --- /dev/null +++ b/modules/Admin/Language/fr/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Aller à la page du podcast', + 'rss_feed' => 'Flux RSS', + 'dashboard' => 'Tableau de bord du podcast', + 'podcast-view' => 'Accueil', + 'podcast-edit' => 'Modifier le podcast', + 'podcast-persons-manage' => 'Gestion des intervenants', + 'podcast-imports' => 'Imports de podcasts', + 'podcast-imports-sync' => 'Synchronisation des flux', + 'episodes' => 'Épisodes', + 'episode-list' => 'Tous les épisodes', + 'episode-create' => 'Créer un épisode', + 'analytics' => 'Mesures d’audience', + 'podcast-analytics' => 'Vue d’ensemble', + 'podcast-analytics-webpages' => 'Visites des pages web', + 'podcast-analytics-locations' => 'Localisations', + 'podcast-analytics-unique-listeners' => 'Auditeurs uniques', + 'podcast-analytics-players' => 'Lecteurs', + 'podcast-analytics-listening-time' => 'Durée d’écoute', + 'podcast-analytics-time-periods' => 'Périodes', + 'monetization' => 'Monétisation', + 'subscription-list' => 'Tous les abonnements', + 'subscription-create' => 'Ajouter un abonnement', + 'contributors' => 'Contributeurs', + 'contributor-list' => 'Tous les contributeurs', + 'contributor-add' => 'Ajouter un contributeur', + 'broadcast' => 'Diffusion', + 'platforms-podcasting' => 'Apps de Podcasting', + 'platforms-social' => 'Réseaux sociaux', + 'platforms-funding' => 'Liens de financement', + 'podcast-monetization-other' => 'Autre', +]; diff --git a/modules/Admin/Language/fr/Settings.php b/modules/Admin/Language/fr/Settings.php new file mode 100644 index 00000000..f32fc3ec --- /dev/null +++ b/modules/Admin/Language/fr/Settings.php @@ -0,0 +1,58 @@ + 'Paramètres généraux', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Favicon du site', + 'site_icon_delete' => 'Supprimer la favicon du site', + 'site_icon_hint' => 'Les favicons sont ce que vous voyez sur les onglets de votre navigateur, dans votre barre de favoris, et lorsque vous ajoutez un site web en raccourci sur des appareils mobiles.', + 'site_icon_helper' => 'L\'icône doit être carrée et au moins 512px de large et haut.', + 'site_name' => 'Titre du site', + 'site_description' => 'Description du site', + 'submit' => 'Sauvegarder', + 'editSuccess' => 'L’instance a bien été mise à jour !', + 'deleteIconSuccess' => 'La favicon du site a bien été retirée !', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Vous pouvez ici regénérer toutes les images en se basant sur celles qui ont été téléversées à l’origine. À utiliser si vous remarquez qu’il y a des images manquantes. Cette tâche peut prendre du temps.', + 'regenerate' => 'Regénérer les images', + 'regenerationSuccess' => 'Toutes les images ont été regénérées avec succès !', + ], + 'housekeeping' => [ + 'title' => 'Ménage', + 'subtitle' => 'Exécute un nombre de tâches de nettoyage. Utilisez cette fonctionnalité si vous rencontrez des problèmes avec les fichiers multimédias ou l’intégrité des données. Ces tâches peuvent prendre du temps.', + 'reset_counts' => 'Réinitialiser les compteurs', + 'reset_counts_helper' => 'Cette option recalcule et réinitialise les compteurs de données (nombre d’abonné·e·s, de publications, de commentaires, …).', + 'rewrite_media' => 'Réécrire les métadonnées des fichiers média', + 'rewrite_media_helper' => 'Cette option supprimera tous les fichiers média superflus et les recréera (images, fichiers audio, transcripts, chapitrages, …)', + 'rename_episodes_files' => 'Renommer les fichiers audio de l\'épisode', + 'rename_episodes_files_hint' => 'Cette option renommera tous les fichiers audio des épisodes en une chaîne de caractères aléatoire. Utilisez-le si l\'un de vos liens d\'épisodes privés a été divulgué, car cela le masquera efficacement.', + 'clear_cache' => 'Supprimer tout le cache', + 'clear_cache_helper' => 'Cette option supprimera l’intégralité du cache redis ou des fichiers cache du dossier writable/cache.', + 'run' => 'Faire le ménage', + 'runSuccess' => 'Le ménage a été effectué avec succès !', + ], + 'theme' => [ + 'title' => 'Thème', + 'accent_section_title' => 'Couleur d’accentuation', + 'accent_section_subtitle' => 'Sélectionnez une couleur qui déterminera l’apparence de toutes les pages publiques.', + 'pine' => 'Pin', + 'crimson' => 'Cramoisi', + 'amber' => 'Ambre', + 'lake' => 'Lac', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Sauvegarder', + 'setInstanceThemeSuccess' => 'Le thème a bien été mis à jour !', + ], +]; diff --git a/modules/Admin/Language/fr/Soundbite.php b/modules/Admin/Language/fr/Soundbite.php new file mode 100644 index 00000000..d1e7d1dc --- /dev/null +++ b/modules/Admin/Language/fr/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Extraits sonores', + 'soundbite' => 'Extrait sonore', + ], + 'messages' => [ + 'createSuccess' => 'L’extrait sonore a été créé avec succès !', + 'deleteSuccess' => 'L’extrait sonore a bien été supprimé !', + ], + 'form' => [ + 'title' => 'Créer un extrait sonore', + 'soundbite_title' => 'Titre de l’extrait', + 'start_time' => 'Début à', + 'duration' => 'Durée', + 'submit' => 'Créer l’extrait sonore', + ], + 'play' => 'Lancer l’extrait sonore', + 'stop' => 'Arrêter l’extrait sonore', + 'create' => 'Nouvel extrait sonore', + 'delete' => 'Supprimer l’extrait sonore', +]; diff --git a/modules/Admin/Language/fr/Validation.php b/modules/Admin/Language/fr/Validation.php new file mode 100644 index 00000000..2054829b --- /dev/null +++ b/modules/Admin/Language/fr/Validation.php @@ -0,0 +1,17 @@ + + '{field} n’est pas une image ou n’a pas la taille minimale requise.', + 'is_image_ratio' => + '{field} n’est pas une image ou n’est pas au bon format.', + 'is_json' => '{field} contient un JSON non valide.', +]; diff --git a/modules/Admin/Language/fr/VideoClip.php b/modules/Admin/Language/fr/VideoClip.php new file mode 100644 index 00000000..77677563 --- /dev/null +++ b/modules/Admin/Language/fr/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Extraits vidéos', + 'status' => [ + 'label' => 'État', + 'queued' => 'en file d’attente', + 'queued_hint' => 'L’extrait est dans la file d’attente.', + 'pending' => 'en attente', + 'pending_hint' => 'L’extrait va être généré prochainement.', + 'running' => 'en cours', + 'running_hint' => 'L’extrait est en cours de génération.', + 'failed' => 'échec', + 'failed_hint' => 'L’extrait n’a pas pu être généré : erreur du programme.', + 'passed' => 'réussite', + 'passed_hint' => 'L’extrait a été généré avec succès !', + ], + 'clip' => 'Extrait', + 'duration' => 'Durée de traitement', + ], + 'title' => 'Extrait vidéo : {videoClipLabel}', + 'download_clip' => 'Télécharger l’extrait', + 'create' => 'Nouvel extrait vidéo', + 'go_to_page' => 'Aller à la page de l’extrait', + 'retry' => 'Relancer la génération de l’extrait', + 'delete' => 'Supprimer l’extrait', + 'logs' => 'Historique d’exécution', + 'messages' => [ + 'alreadyExistingError' => 'L’extrait vidéo que vous essayez de créer existe déjà !', + 'addToQueueSuccess' => 'L’extrait vidéo a été ajouté à la file d’attente, en attente de création !', + 'deleteSuccess' => 'L’extrait vidéo a bien été supprimé !', + ], + 'format' => [ + 'landscape' => 'Paysage', + 'portrait' => 'Portrait', + 'squared' => 'Carré', + ], + 'form' => [ + 'title' => 'Nouvel extrait vidéo', + 'params_section_title' => 'Paramètres de l’extrait vidéo', + 'clip_title' => 'Titre de l’extrait', + 'format' => [ + 'label' => 'Choisissez un format', + 'landscape_hint' => 'Avec un ratio de 16/9, les vidéos en paysage sont adaptées pour PeerTube, Youtube et Vimeo.', + 'portrait_hint' => 'Avec un ratio de 9/16, les vidéos en portrait sont adaptées pour TikTok, les Youtube shorts and les stories Instagram.', + 'squared_hint' => 'Avec un ratio de 1/1, les vidéos carrées sont adaptées pour Mastodon, Facebook, Twitter et LinkedIn.', + ], + 'theme' => 'Sélectionnez un thème', + 'start_time' => 'Démarrer à', + 'duration' => 'Durée', + 'trim_start' => 'Rogner le début', + 'trim_end' => 'Rogner la fin', + 'submit' => 'Créer un extrait vidéo', + ], + 'requirements' => [ + 'title' => 'Outils manquants', + 'missing' => 'Il vous manque des outils. Assurez vous d’avoir ajouté tous les outils nécessaires pour accéder au fomulaire de génération d’extrait vidéo !', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Librairie Freetype pour GD', + 'transcript' => 'Fichier de transcription (.srt)', + ], +]; diff --git a/modules/Admin/Language/fr2/AboutCastopod.php b/modules/Admin/Language/fr2/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/fr2/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/fr2/Breadcrumb.php b/modules/Admin/Language/fr2/Breadcrumb.php new file mode 100644 index 00000000..52e423ee --- /dev/null +++ b/modules/Admin/Language/fr2/Breadcrumb.php @@ -0,0 +1,57 @@ + 'fil d’Ariane', + config('Admin') + ->gateway => 'Accueil', + 'podcasts' => 'podcasts', + 'episodes' => 'épisodes', + 'subscriptions' => 'abonnements', + 'contributors' => 'contributeurs', + 'pages' => 'pages', + 'settings' => 'paramètres', + 'theme' => 'thème', + 'about' => 'à propos', + 'add' => 'ajouter', + 'new' => 'créer', + 'edit' => 'modifier', + 'persons' => 'intervenants', + 'publish' => 'publier', + 'publish-edit' => 'modifier la publication', + 'publish-date-edit' => 'modifier la date de publication', + 'unpublish' => 'dépublier', + 'delete' => 'supprimer', + 'remove' => 'retirer', + 'fediverse' => 'fédiverse', + 'blocked-actors' => 'utilisateurs bloqués', + 'blocked-domains' => 'domaines bloqués', + 'users' => 'utilisateurs', + 'my-account' => 'mon compte', + 'change-password' => 'changer le mot de passe', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'plateformes', + 'social' => 'réseaux sociaux', + 'funding' => 'financement', + 'monetization-other' => 'other monetization', + 'analytics' => 'mesure d’audience', + 'locations' => 'localisation', + 'webpages' => 'pages web', + 'unique-listeners' => 'auditeurs uniques', + 'players' => 'lecteurs', + 'listening-time' => 'durée d’écoute', + 'time-periods' => 'périodes', + 'soundbites' => 'extraits sonores', + 'video-clips' => 'extraits vidéo', + 'embed' => 'lecteur intégré', + 'notifications' => 'notifications', + 'suspend' => 'suspendre', +]; diff --git a/modules/Admin/Language/fr2/Charts.php b/modules/Admin/Language/fr2/Charts.php new file mode 100644 index 00000000..22759389 --- /dev/null +++ b/modules/Admin/Language/fr2/Charts.php @@ -0,0 +1,41 @@ + 'Téléchargements d’épisodes par service (la semaine dernière)', + 'by_player_weekly' => 'Téléchargements d’épisodes par lecteur (la semaine dernière)', + 'by_player_yearly' => 'Téléchargements d’épisodes par lecteur (cette année)', + 'by_device_weekly' => 'Téléchargements d’épisodes par appareil (la semaine dernière)', + 'by_os_weekly' => 'Téléchargements d’épisodes par OS (la semaine dernière)', + 'podcast_by_region' => 'Téléchargements d’épisodes par région (la semaine dernière)', + 'unique_daily_listeners' => 'Auditeurs uniques quotidiens', + 'unique_monthly_listeners' => 'Auditeurs uniques mensuels', + 'by_browser' => 'Fréquentation des pages web par navigateur (la semaine dernière)', + 'podcast_by_day' => 'Téléchargements quotidiens d’épisodes', + 'podcast_by_month' => 'Téléchargements mensuels d’épisodes', + 'episode_by_day' => 'Téléchargements quotidiens de l’épisode (les 60 premiers jours)', + 'episode_by_month' => 'Téléchargements mensuels de l’épisode', + 'episodes_by_day' => + 'Téléchargements des 5 derniers épisodes (lors de leurs 60 premiers jours)', + 'by_country_weekly' => 'Téléchargements d’épisodes par pays (la dernière semaine)', + 'by_country_yearly' => 'Téléchargements d’épisodes par pays (l\'année dernière)', + 'by_domain_weekly' => 'Fréquentation des pages web par origine (la semaine dernière)', + 'by_domain_yearly' => 'Fréquentation des pages web par origine (la semaine dernière)', + 'by_entry_page' => 'Fréquentation des pages web par page d’entrée (la semaine dernière)', + 'podcast_bots' => 'Robots (bots)', + 'daily_listening_time' => 'Durée quotidienne d’écoute cumulée', + 'monthly_listening_time' => 'Durée mensuelle d’écoute cumulée', + 'by_weekday' => 'Par jour de la semaine (les 60 derniers jours)', + 'by_hour' => 'Par heure de la journée (les 60 derniers jours)', + 'podcast_by_bandwidth' => 'Bande passante quotidienne consommée (en Mo)', + 'total_storage_by_month' => 'Stockage mensuel (en Mo)', + 'total_bandwidth_by_month' => 'Bande passante mensuelle utilisée (en Mo)', + 'total_bandwidth_by_month_limit' => 'Limité à {totalBandwidth} par mois', +]; diff --git a/modules/Admin/Language/fr2/Common.php b/modules/Admin/Language/fr2/Common.php new file mode 100644 index 00000000..73daacf7 --- /dev/null +++ b/modules/Admin/Language/fr2/Common.php @@ -0,0 +1,52 @@ + 'Oui', + 'no' => 'Non', + 'cancel' => 'Annuler', + 'optional' => 'Optionnel', + 'more' => 'Plus', + 'no_data' => 'Aucune donnée trouvée  !', + 'close' => 'Fermer', + 'edit' => 'Modifier', + 'copy' => 'Copier', + 'copied' => 'Copié  !', + 'home' => 'Accueil', + 'explicit' => 'Explicite', + 'powered_by' => 'Propulsé par {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} sur {pageCount}', + 'go_back' => 'Retour en arrière', + 'forms' => [ + 'editor' => [ + 'write' => 'Écrire', + 'preview' => 'Aperçu', + 'help' => 'Propulsé par markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Cliquez pour selectionner', + 'loadingText' => 'Chargement…', + 'noResultsText' => 'Aucun résultat trouvé', + 'noChoicesText' => 'Aucune sélection possible', + 'maxItemText' => 'Impossible de rajouter un élément', + ], + 'upload_file' => 'Téléverser un fichier', + 'remote_url' => 'URL distante', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Lire', + 'playing' => 'En cours', + ], + 'size_limit' => 'Taille maximale : {0}.', + 'choose_interact' => 'Choisissez le mode d\'interaction', + 'view' => 'Voir', +]; diff --git a/modules/Admin/Language/fr2/Countries.php b/modules/Admin/Language/fr2/Countries.php new file mode 100644 index 00000000..a0e70692 --- /dev/null +++ b/modules/Admin/Language/fr2/Countries.php @@ -0,0 +1,264 @@ + 'Andorre', + 'AE' => 'Émirats Arabes Unis', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua-Et-Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albanie', + 'AM' => 'Arménie', + 'AO' => 'Angola', + 'AQ' => 'Antarctique', + 'AR' => 'Argentine', + 'AS' => 'Samoa Américaines', + 'AT' => 'Autriche', + 'AU' => 'Australie', + 'AW' => 'Aruba', + 'AX' => 'Åland, Îles', + 'AZ' => 'Azerbaïdjan', + 'BA' => 'Bosnie-Herzégovine', + 'BB' => 'Barbade', + 'BD' => 'Bangladesh', + 'BE' => 'Belgique', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgarie', + 'BH' => 'Bahreïn', + 'BI' => 'Burundi', + 'BJ' => 'Bénin', + 'BL' => 'Saint-Barthélemy', + 'BM' => 'Bermudes', + 'BN' => 'Brunéi Darussalam', + 'BO' => 'Bolivie, État Plurinational De', + 'BQ' => 'Bonaire, Saint-Eustache Et Saba', + 'BR' => 'Brésil', + 'BS' => 'Bahamas', + 'BT' => 'Bhoutan', + 'BV' => 'Bouvet, Île', + 'BW' => 'Botswana', + 'BY' => 'Bélarus', + 'BZ' => 'Bélize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling), Îles', + 'CD' => 'Congo, La République Démocratique Du', + 'CF' => 'Centrafricaine, République', + 'CG' => 'Congo', + 'CH' => 'Suisse', + 'CI' => "Côte D’ivoire", + 'CK' => 'Cook, Îles', + 'CL' => 'Chili', + 'CM' => 'Cameroun', + 'CN' => 'Chine', + 'CO' => 'Colombie', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cap-Vert', + 'CW' => 'Curaçao', + 'CX' => 'Christmas, Île', + 'CY' => 'Chypre', + 'CZ' => 'Tchéquie', + 'DE' => 'Allemagne', + 'DJ' => 'Djibouti', + 'DK' => 'Danemark', + 'DM' => 'Dominique', + 'DO' => 'République Dominicaine', + 'DZ' => 'Algérie', + 'EC' => 'Équateur', + 'EE' => 'Estonie', + 'EG' => 'Égypte', + 'EH' => 'Sahara Occidental', + 'ER' => 'Érythrée', + 'ES' => 'Espagne', + 'ET' => 'Éthiopie', + 'FI' => 'Finlande', + 'FJ' => 'Fidji', + 'FK' => 'Falkland, Îles (Malvinas)', + 'FM' => 'Micronésie, États Fédérés De', + 'FO' => 'Féroé, Îles', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'Royaume-Uni', + 'GD' => 'Grenade', + 'GE' => 'Géorgie', + 'GF' => 'Guyane Française', + 'GG' => 'Guernesey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenland', + 'GM' => 'Gambie', + 'GN' => 'Guinée', + 'GP' => 'Guadeloupe', + 'GQ' => 'Guinée Équatoriale', + 'GR' => 'Grèce', + 'GS' => 'Géorgie Du Sud Et Les Îles Sandwich Du Sud', + 'GT' => 'Guatémala', + 'GU' => 'Guam', + 'GW' => 'Guinée-Bissau', + 'GY' => 'Guyane', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Et Macdonald, Îles', + 'HN' => 'Honduras', + 'HR' => 'Croatie', + 'HT' => 'Haïti', + 'HU' => 'Hongrie', + 'ID' => 'Indonésie', + 'IE' => 'Irlande', + 'IL' => 'Israël', + 'IM' => 'Île De Man', + 'IN' => 'Inde', + 'IO' => 'Océan Indien, Territoire Britannique De L’', + 'IQ' => 'Irak', + 'IR' => 'Iran, République Islamique D’', + 'IS' => 'Islande', + 'IT' => 'Italie', + 'JE' => 'Jersey', + 'JM' => 'Jamaïque', + 'JO' => 'Jordanie', + 'JP' => 'Japon', + 'KE' => 'Kenya', + 'KG' => 'Kirghizistan', + 'KH' => 'Cambodge', + 'KI' => 'Kiribati', + 'KM' => 'Comores', + 'KN' => 'Saint-Kitts-Et-Nevis', + 'KP' => "Corée, République Populaire Démocratique De", + 'KR' => 'Corée, République De', + 'KW' => 'Koweït', + 'KY' => 'Caïmanes, Îles', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao, République Démocratique Populaire", + 'LB' => 'Liban', + 'LC' => 'Sainte-Lucie', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Libéria', + 'LS' => 'Lesotho', + 'LT' => 'Lituanie', + 'LU' => 'Luxembourg', + 'LV' => 'Lettonie', + 'LY' => 'Libye', + 'MA' => 'Maroc', + 'MC' => 'Monaco', + 'MD' => 'Moldavie', + 'ME' => 'Monténégro', + 'MF' => 'Saint-Martin (Partie Française)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall, Îles', + 'MK' => 'République De Macédoine', + 'ML' => 'Mali', + 'MM' => 'Birmanie', + 'MN' => 'Mongolie', + 'MO' => 'Macao', + 'MP' => 'Mariannes Du Nord, Îles', + 'MQ' => 'Martinique', + 'MR' => 'Mauritanie', + 'MS' => 'Montserrat', + 'MT' => 'Malte', + 'MU' => 'Maurice', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexique', + 'MY' => 'Malaisie', + 'MZ' => 'Mozambique', + 'N/A' => 'Non Applicable (IP locale…)', + 'NA' => 'Namibie', + 'NC' => 'Nouvelle-Calédonie', + 'NE' => 'Niger', + 'NF' => 'Norfolk, Île', + 'NG' => 'Nigéria', + 'NI' => 'Nicaragua', + 'NL' => 'Pays-Bas', + 'NO' => 'Norvège', + 'NP' => 'Népal', + 'NR' => 'Nauru', + 'NU' => 'Niué', + 'NZ' => 'Nouvelle-Zélande', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Pérou', + 'PF' => 'Polynésie Française', + 'PG' => 'Papouasie-Nouvelle-Guinée', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Pologne', + 'PM' => 'Saint-Pierre-Et-Miquelon', + 'PN' => 'Îles Pitcairn', + 'PR' => 'Porto Rico', + 'PS' => 'État De Palestine', + 'PT' => 'Portugal', + 'PW' => 'Palaos', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'La Réunion', + 'RO' => 'Roumanie', + 'RS' => 'Serbie', + 'RU' => 'Russie, Fédération De', + 'RW' => 'Rwanda', + 'SA' => 'Arabie Saoudite', + 'SB' => 'Salomon, Îles', + 'SC' => 'Seychelles', + 'SD' => 'Soudan', + 'SE' => 'Suède', + 'SG' => 'Singapour', + 'SH' => 'Sainte-Hélène, Ascension Et Tristan Da Cunha', + 'SI' => 'Slovénie', + 'SJ' => 'Svalbard Et Île Jan Mayen', + 'SK' => 'Slovaquie', + 'SL' => 'Sierra Leone', + 'SM' => 'Saint-Marin', + 'SN' => 'Sénégal', + 'SO' => 'Somalie', + 'SR' => 'Suriname', + 'SS' => 'Soudan Du Sud', + 'ST' => 'Sao Tomé-Et-Principe', + 'SV' => 'El Salvador', + 'SX' => 'Saint-Martin (Partie Néerlandaise)', + 'SY' => 'Syrienne, République Arabe', + 'SZ' => 'Eswatini', + 'TC' => 'Turks Et Caïques, Îles', + 'TD' => 'Tchad', + 'TF' => 'Terres Australes Françaises', + 'TG' => 'Togo', + 'TH' => 'Thaïlande', + 'TJ' => 'Tadjikistan', + 'TK' => 'Tokélaou', + 'TL' => 'Timor oriental', + 'TM' => 'Turkménistan', + 'TN' => 'Tunisie', + 'TO' => 'Tonga', + 'TR' => 'Turquie', + 'TT' => 'Trinité-Et-Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taïwan', + 'TZ' => 'Tanzanie, République Unie De', + 'UA' => 'Ukraine', + 'UG' => 'Ouganda', + 'UM' => 'Îles Mineures Éloignées Des États-Unis', + 'US' => 'États-Unis', + 'UY' => 'Uruguay', + 'UZ' => 'Ouzbékistan', + 'VA' => 'Saint-Siège (État de la Cité du Vatican)', + 'VC' => 'Saint-Vincent-Et-Les-Grenadines', + 'VE' => 'Venezuela, République Bolivarienne Du', + 'VG' => 'Îles Vierges Britanniques', + 'VI' => 'Îles Vierges des États-Unis', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis-Et-Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yémen', + 'YT' => 'Mayotte', + 'ZA' => 'Afrique Du Sud', + 'ZM' => 'Zambie', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/fr2/Dashboard.php b/modules/Admin/Language/fr2/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/fr2/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/fr2/Episode.php b/modules/Admin/Language/fr2/Episode.php new file mode 100644 index 00000000..98838164 --- /dev/null +++ b/modules/Admin/Language/fr2/Episode.php @@ -0,0 +1,225 @@ + 'Saison {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Épisode {episodeNumber}', + 'number_abbr' => 'Ép. {episodeNumber}', + 'season_episode' => 'Saison {seasonNumber} épisode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}:E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# commentaire} + other {# commentaires} + }', + 'all_podcast_episodes' => 'Tous les épisodes du podcast', + 'back_to_podcast' => 'Revenir au podcast', + 'edit' => 'Modifier', + 'preview' => 'Preview', + 'publish' => 'Publier', + 'publish_edit' => 'Modifier la publication', + 'publish_date_edit' => 'Modifier la date de publication', + 'unpublish' => 'Dépublier', + 'publish_error' => 'L’épisode est déjà publié.', + 'publish_edit_error' => 'L’épisode est déjà publié.', + 'publish_cancel_error' => 'L’épisode est déjà publié.', + 'publish_date_edit_error' => 'L\'épisode n\'a pas encore été publié, vous ne pouvez pas modifier sa date de publication.', + 'publish_date_edit_future_error' => 'La date de publication de l\'épisode ne peut être définie qu\'à une date antérieure ! Si vous souhaitez la replanifier, dépubliez-le d\'abord.', + 'publish_date_edit_success' => 'La date de publication de l\'épisode a été mise à jour avec succès !', + 'unpublish_error' => 'L’épisode n’est pas publié.', + 'delete' => 'Supprimer', + 'go_to_page' => 'Voir', + 'create' => 'Ajouter un épisode', + 'publication_status' => [ + 'published' => 'Publié', + 'with_podcast' => 'Publié', + 'scheduled' => 'Planifié', + 'not_published' => 'Non publié', + ], + 'with_podcast_hint' => 'Publier en même temps que le podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Rechercher un épisode', + 'clear' => 'Effacer la recherche', + 'submit' => 'Recherche', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# épisode} + other {# épisodes} + }', + 'episode' => 'Épisode', + 'visibility' => 'Visibilité', + 'downloads' => 'Downloads', + 'comments' => 'Commentaires', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'L’épisode a été créé avec succès  !', + 'editSuccess' => 'L’épisode a bien été mis à jour  !', + 'publishSuccess' => '{publication_status, select, + published {Épisode publié avec succès !} + scheduled {La publication de l\'épisode est planifiée avec succès !} + with_podcast {Cet épisode sera publié en même temps que le podcast.} + other {Cet épisode n\'est pas publié.} + }', + 'publishCancelSuccess' => 'La publication de l’épisode a bien été annulée  !', + 'unpublishBeforeDeleteTip' => 'Vous devez dépublier l\'épisode avant de le supprimer.', + 'scheduleDateError' => 'La date de planification doit être définie !', + 'deletePublishedEpisodeError' => 'Vous devez dépublier l\'épisode avant de le supprimer.', + 'deleteSuccess' => 'L\'épisode a bien été supprimé !', + 'deleteError' => 'Impossible de supprimer {type, select, + transcript {la transcription} + chapters {les chapitres} + image {la couverture} + audio {l\'audio} + other {le média} + } de l\'épisode.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Il existe déjà un épisode avec le slug choisi.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapitrage', + 'chapters_hint' => 'Le fichier doit être en format “JSON Chapters”.', + 'chapters_download' => 'Télécharger le chapitrage', + 'chapters_file' => 'Fichier de chapitrage', + 'chapters_remote_url' => 'URL distante pour le fichier de chapitrage', + 'chapters_file_delete' => 'Supprimer le fichier de chapitrage', + 'advanced_section_title' => 'Paramètres avancés', + 'advanced_section_subtitle' => + 'Si vous avez besoin d’une balise RSS que Castopod ne couvre pas, définissez-la ici.', + 'custom_rss' => 'Balises RSS personnalisées pour l’épisode', + 'custom_rss_hint' => 'Ceci sera injecté dans la balise ❬item❭.', + 'block' => 'L\'épisode doit être masqué dans les catalogues publics', + 'block_hint' => + 'Statut caché ou visible de l\'épisode : activer ceci empêche l\'épisode d\'apparaître dans les Apple Podcasts, Google Podcasts, et toutes les applications tierces qui utilisent ces répertoires. (Sans garantie)', + 'submit_create' => 'Créer l’épisode', + 'submit_edit' => 'Enregistrer l’épisode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Retour au tableau de bord de l’épisode', + 'post' => 'Votre message de publication', + 'post_hint' => + "Écrivez un message pour annoncer la publication de votre épisode. Ce message sera diffusé à toutes les personnes qui vous suivent dans le fédiverse et mis en évidence sur la page d’accueil de votre podcast.", + 'message_placeholder' => 'Entrez votre message…', + 'publication_date' => 'Date de publication', + 'publication_method' => [ + 'now' => 'Maintenant', + 'schedule' => 'Planifier', + 'with_podcast' => 'Publier en même temps que le podcast', + ], + 'scheduled_publication_date' => 'Date de publication programmée', + 'scheduled_publication_date_clear' => 'Effacer la date de publication', + 'scheduled_publication_date_hint' => + 'Vous pouvez planifier la sortie de l’épisode en saisissant une date de publication future. Ce champ doit être au format YYYY-MM-DD HH:mm', + 'submit' => 'Publier', + 'submit_edit' => 'Modifier la publication', + 'cancel_publication' => 'Annuler la publication', + 'message_warning' => 'Vous n’avez pas saisi de message pour l’annonce de votre épisode  !', + 'message_warning_hint' => 'Ajouter un message augmente l’engagement sur les réseaux sociaux, donnant une meilleure visibilité à votre épisode.', + 'message_warning_submit' => 'Publier quand même', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nouvelle date de publication', + 'new_publication_date_hint' => 'Doit être défini à une date antérieure.', + 'submit' => 'Modifier la date de publication', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Dépublier l'épisode supprimera tous les commentaires et messages qui lui sont associés et le retirera du flux RSS du podcast.", + 'understand' => 'Je comprends, je veux dépublier l’épisode', + 'submit' => 'Dépublier', + ], + 'delete_form' => [ + 'disclaimer' => + "La suppression de l'épisode supprimera tous les fichiers multimédia, les commentaires, les clips vidéo et les parties sonores qui y sont associés.", + 'understand' => 'Je comprends, je veux supprimer l’épisode', + 'submit' => 'Supprimer', + ], + 'embed' => [ + 'title' => 'Lecteur intégré', + 'label' => + 'Sélectionnez une couleur de thème, copiez le code dans le presse-papier, puis collez-le sur votre site internet.', + 'clipboard_iframe' => 'Copier le code du lecteur intégré dans le presse papier', + 'clipboard_url' => 'Copier l’adresse dans le presse papier', + 'dark' => 'Sombre', + 'dark-transparent' => 'Sombre transparent', + 'light' => 'Clair', + 'light-transparent' => 'Clair transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/fr2/EpisodeNavigation.php b/modules/Admin/Language/fr2/EpisodeNavigation.php new file mode 100644 index 00000000..2f7ff829 --- /dev/null +++ b/modules/Admin/Language/fr2/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Aller à la page de l’épisode', + 'dashboard' => 'Tableau de bord de l’épisode', + 'episode-view' => 'Accueil', + 'episode-edit' => 'Modifier l’épisode', + 'episode-persons-manage' => 'Gérer les intervenants', + 'embed-add' => 'Lecteur intégré', + 'clips' => 'Extraits', + 'video-clips-list' => 'Extraits vidéo', + 'video-clips-create' => 'Nouvel extrait vidéo', + 'soundbites-list' => 'Extraits sonores', + 'soundbites-create' => 'Nouvel extrait sonore', +]; diff --git a/modules/Admin/Language/fr2/Fediverse.php b/modules/Admin/Language/fr2/Fediverse.php new file mode 100644 index 00000000..3e7a0b26 --- /dev/null +++ b/modules/Admin/Language/fr2/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'L’utilisateur n’a pu être trouvé  !', + 'blockActorSuccess' => '{actor} a été bloqué  !', + 'unblockActorSuccess' => 'L’utilisateur a été débloqué  !', + 'blockDomainSuccess' => '{domain} a été bloqué  !', + 'unblockDomainSuccess' => '{domain} a été débloqué  !', + ], + 'blocked_actors' => 'Utilisateurs bloqués', + 'blocked_domains' => 'Domaines bloqués', + 'block_lists_form' => [ + 'handle' => 'Identifiant', + 'handle_hint' => 'Saisissez l’utilisateur @nom@domaine.', + 'domain' => 'Nom de domaine', + 'submit' => 'Bloquer !', + ], + 'list' => [ + 'actor' => 'Utilisateur', + 'domain' => 'Nom de domaine', + 'unblock' => 'Débloquer', + ], +]; diff --git a/modules/Admin/Language/fr2/Home.php b/modules/Admin/Language/fr2/Home.php new file mode 100644 index 00000000..0ec83396 --- /dev/null +++ b/modules/Admin/Language/fr2/Home.php @@ -0,0 +1,14 @@ + 'Tous les podcasts', + 'no_podcast' => 'Aucun podcast trouvé', +]; diff --git a/modules/Admin/Language/fr2/Install.php b/modules/Admin/Language/fr2/Install.php new file mode 100644 index 00000000..b7d6ea1b --- /dev/null +++ b/modules/Admin/Language/fr2/Install.php @@ -0,0 +1,61 @@ + 'Configuration manuelle', + 'manual_config_subtitle' => + 'Créez un fichier `.env` qui contient tous vos paramètres puis rafraîchissez la page pour continuer l’installation.', + 'form' => [ + 'instance_config' => 'Paramètres de l’instance', + 'hostname' => 'Nom d’hôte', + 'media_base_url' => 'Adresse racine des médias', + 'media_base_url_hint' => + 'Si vous utilisez un CDN et/ou un service de mesure d’audience externe, vous pouvez les définir ici.', + 'admin_gateway' => 'Adresse d’administration', + 'admin_gateway_hint' => + 'Chemin pour accéder à l’administration (par exemple https://example.com/cp-admin). Il est défini par défaut à cp-admin, nous vous recommandons de le changer par mesure de sécurité.', + 'auth_gateway' => 'Adresse d’authentification', + 'auth_gateway_hint' => + 'Le chemin des pages d’authentication (par exemple https://example.fr/cp-auth). Il est défini par défaut à cp-auth, nous vous recommandons de le changer par mesure de sécurité.', + 'database_config' => 'Paramètres de la base de données', + 'database_config_hint' => + 'Castopod doit se connecter à votre base de données MySQL (ou MariaDB). Si vous ne disposez pas de ces informations, merci de contacter l’administrateur du serveur.', + 'db_hostname' => 'Nom d’hôte (ou IP) de la base de données', + 'db_name' => 'Nom de la base de données', + 'db_username' => 'Utilisateur de la base de données', + 'db_password' => 'Mot de passe de la base de données', + 'db_prefix' => 'Préfixe des tables', + 'db_prefix_hint' => + "Le préfixe des noms de tables de Castopod, laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.", + 'cache_config' => 'Paramètres du cache', + 'cache_config_hint' => + 'Sélectionnez votre gestionnaire de cache préféré. Laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.', + 'cache_handler' => 'Gestionnaire de cache', + 'cacheHandlerOptions' => [ + 'file' => 'Fichier', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Suivant', + 'submit' => 'Terminer l’installation', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/fr2/Navigation.php b/modules/Admin/Language/fr2/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/fr2/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/fr2/Notifications.php b/modules/Admin/Language/fr2/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/fr2/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/fr2/Page.php b/modules/Admin/Language/fr2/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/fr2/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/fr2/Pager.php b/modules/Admin/Language/fr2/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/fr2/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/fr2/Person.php b/modules/Admin/Language/fr2/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/fr2/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/fr2/Platforms.php b/modules/Admin/Language/fr2/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/fr2/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/fr2/Podcast.php b/modules/Admin/Language/fr2/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/fr2/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/fr2/PodcastNavigation.php b/modules/Admin/Language/fr2/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/fr2/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/fr2/Settings.php b/modules/Admin/Language/fr2/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/fr2/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/fr2/Soundbite.php b/modules/Admin/Language/fr2/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/fr2/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/fr2/Validation.php b/modules/Admin/Language/fr2/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/fr2/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/fr2/VideoClip.php b/modules/Admin/Language/fr2/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/fr2/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/gd/AboutCastopod.php b/modules/Admin/Language/gd/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/gd/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/gd/Admin.php b/modules/Admin/Language/gd/Admin.php new file mode 100644 index 00000000..5e394237 --- /dev/null +++ b/modules/Admin/Language/gd/Admin.php @@ -0,0 +1,15 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'choose_interact' => 'Choose how to interact', +]; diff --git a/modules/Admin/Language/gd/Breadcrumb.php b/modules/Admin/Language/gd/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/gd/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/gd/Charts.php b/modules/Admin/Language/gd/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/gd/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/gd/Common.php b/modules/Admin/Language/gd/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/gd/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/gd/Countries.php b/modules/Admin/Language/gd/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/gd/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/gd/Dashboard.php b/modules/Admin/Language/gd/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/gd/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/gd/Episode.php b/modules/Admin/Language/gd/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/gd/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/gd/EpisodeNavigation.php b/modules/Admin/Language/gd/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/gd/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/gd/Fediverse.php b/modules/Admin/Language/gd/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/gd/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/gd/Home.php b/modules/Admin/Language/gd/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/gd/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/gd/Install.php b/modules/Admin/Language/gd/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/gd/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/gd/Navigation.php b/modules/Admin/Language/gd/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/gd/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/gd/Notifications.php b/modules/Admin/Language/gd/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/gd/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/gd/Page.php b/modules/Admin/Language/gd/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/gd/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/gd/Pager.php b/modules/Admin/Language/gd/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/gd/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/gd/Person.php b/modules/Admin/Language/gd/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/gd/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/gd/Platforms.php b/modules/Admin/Language/gd/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/gd/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/gd/Podcast.php b/modules/Admin/Language/gd/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/gd/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/gd/PodcastNavigation.php b/modules/Admin/Language/gd/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/gd/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/gd/Settings.php b/modules/Admin/Language/gd/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/gd/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/gd/Soundbite.php b/modules/Admin/Language/gd/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/gd/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/gd/Validation.php b/modules/Admin/Language/gd/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/gd/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/gd/VideoClip.php b/modules/Admin/Language/gd/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/gd/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/gl/AboutCastopod.php b/modules/Admin/Language/gl/AboutCastopod.php new file mode 100644 index 00000000..3c26b13f --- /dev/null +++ b/modules/Admin/Language/gl/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Acerca de Castopod', + 'host_name' => 'Nome do servidor', + 'version' => 'Versión de Castopod', + 'php_version' => 'Versión de PHP', + 'os' => 'Sistema Operativo', + 'languages' => 'Idiomas', + 'update_database' => 'Anovar base de datos', + 'messages' => [ + 'databaseUpdateSuccess' => 'A base de datos está ao día!', + ], +]; diff --git a/modules/Admin/Language/gl/Breadcrumb.php b/modules/Admin/Language/gl/Breadcrumb.php new file mode 100644 index 00000000..fa515f15 --- /dev/null +++ b/modules/Admin/Language/gl/Breadcrumb.php @@ -0,0 +1,57 @@ + 'menú', + config('Admin') + ->gateway => 'Inicio', + 'podcasts' => 'podcasts', + 'episodes' => 'episodios', + 'subscriptions' => 'subscricións', + 'contributors' => 'contribúen', + 'pages' => 'páxinas', + 'settings' => 'axustes', + 'theme' => 'decorado', + 'about' => 'acerca de', + 'add' => 'engadir', + 'new' => 'novo', + 'edit' => 'editar', + 'persons' => 'persoas', + 'publish' => 'publicar', + 'publish-edit' => 'editar publicación', + 'publish-date-edit' => 'editar data de publicación', + 'unpublish' => 'retirar publicación', + 'delete' => 'eliminar', + 'remove' => 'eliminar', + 'fediverse' => 'fediverso', + 'blocked-actors' => 'contas bloqueadas', + 'blocked-domains' => 'dominios bloqueados', + 'users' => 'usuarias', + 'my-account' => 'a miña conta', + 'change-password' => 'cambiar contrasinal', + 'imports' => 'importacións', + 'sync-feeds' => 'sincronizar fontes', + 'platforms' => 'plataformas', + 'social' => 'redes sociais', + 'funding' => 'financiamento', + 'monetization-other' => 'outros xeitos', + 'analytics' => 'análise', + 'locations' => 'localizacións', + 'webpages' => 'páxinas web', + 'unique-listeners' => 'oíntes únicos', + 'players' => 'reprodutores', + 'listening-time' => 'tempo de escoita', + 'time-periods' => 'período de tempo', + 'soundbites' => 'anaquiños', + 'video-clips' => 'clips de vídeo', + 'embed' => 'reprodutor para incluír', + 'notifications' => 'notificacións', + 'suspend' => 'suspender', +]; diff --git a/modules/Admin/Language/gl/Charts.php b/modules/Admin/Language/gl/Charts.php new file mode 100644 index 00000000..0e232ad4 --- /dev/null +++ b/modules/Admin/Language/gl/Charts.php @@ -0,0 +1,41 @@ + 'Descargas do episodio por servizo (na última semana)', + 'by_player_weekly' => 'Descargas do episodio por reprodutor (na última semana)', + 'by_player_yearly' => 'Descargas do episodio por reprodutor (no último ano)', + 'by_device_weekly' => 'Descargas do episodio por dispositivo (na última semana)', + 'by_os_weekly' => 'Descargas do episodio por SO (na última semana)', + 'podcast_by_region' => 'Descargas do episodio por rexión (na última semana)', + 'unique_daily_listeners' => 'Oíntes únicas diarias', + 'unique_monthly_listeners' => 'Oíntes únicas mensuais', + 'by_browser' => 'Uso de páxinas web por navegador (na última semana)', + 'podcast_by_day' => 'Descargas diarias do episodio', + 'podcast_by_month' => 'Descargas mensuais do episodio', + 'episode_by_day' => 'Descargas diarias do episodio (primeiros 60 días)', + 'episode_by_month' => 'Descargas mensuais do episodio', + 'episodes_by_day' => + 'Descargas dos últimos 5 episodios (durante os primeiros 60 días)', + 'by_country_weekly' => 'Descargas do episodio por país (na última semana)', + 'by_country_yearly' => 'Descargas de episodio por país (no último ano)', + 'by_domain_weekly' => 'Visitas a páxinas web por orixe (na última semana)', + 'by_domain_yearly' => 'Visitas a páxinas web por orixe (no último ano)', + 'by_entry_page' => 'Visitas a páxinas we por páxina de entrada (na última semana)', + 'podcast_bots' => 'Bots (rastrexadores)', + 'daily_listening_time' => 'Tempo de escoita acumulado diario', + 'monthly_listening_time' => 'Tempo de escoita acumulado mensual', + 'by_weekday' => 'Por día da semana (nos últimos 60 días)', + 'by_hour' => 'Por hora do día (nos últimos 60 días)', + 'podcast_by_bandwidth' => 'Ancho de banda diario utilizado (en MB)', + 'total_storage_by_month' => 'Almacenaxe mensual (en MB)', + 'total_bandwidth_by_month' => 'Ancho de banda mensual utilizado (en MB)', + 'total_bandwidth_by_month_limit' => 'Limitado a {totalBandwidth} ao mes', +]; diff --git a/modules/Admin/Language/gl/Common.php b/modules/Admin/Language/gl/Common.php new file mode 100644 index 00000000..97f03466 --- /dev/null +++ b/modules/Admin/Language/gl/Common.php @@ -0,0 +1,52 @@ + 'Si', + 'no' => 'Non', + 'cancel' => 'Cancelar', + 'optional' => 'Optativo', + 'more' => 'Máis', + 'no_data' => 'Non se atopan datos!', + 'close' => 'Pechar', + 'edit' => 'Editar', + 'copy' => 'Copiar', + 'copied' => 'Copiado!', + 'home' => 'Inicio', + 'explicit' => 'Explícito', + 'powered_by' => 'Grazas a {castopod}', + 'actions' => 'Accións', + 'pageInfo' => 'Páxina {currentPage} de {pageCount}', + 'go_back' => 'Volver', + 'forms' => [ + 'editor' => [ + 'write' => 'Escribir', + 'preview' => 'Vista previa', + 'help' => 'Con soporte markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Preme para seleccionar', + 'loadingText' => 'Cargando…', + 'noResultsText' => 'Non se atoparon resultados', + 'noChoicesText' => 'Non hai opcións para elexir', + 'maxItemText' => 'Non podes engadir máis elementos', + ], + 'upload_file' => 'Subir un ficheiro', + 'remote_url' => 'URL remoto', + 'save' => 'Gardar', + ], + 'play_episode_button' => [ + 'play' => 'Reproducir', + 'playing' => 'Reproducindo', + ], + 'size_limit' => 'Límite do tamaño: {0}.', + 'choose_interact' => 'Elixe como interactuar', + 'view' => 'Ver', +]; diff --git a/modules/Admin/Language/gl/Countries.php b/modules/Admin/Language/gl/Countries.php new file mode 100644 index 00000000..c79e1632 --- /dev/null +++ b/modules/Admin/Language/gl/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emiratos Árabes Unidos', + 'AF' => 'Afganistán', + 'AG' => 'Antigua e Barbuda', + 'AI' => 'Anguila', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antártida', + 'AR' => 'Arxentina', + 'AS' => 'Samoa Americana', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Illas Åland', + 'AZ' => 'Acerbaixán', + 'BA' => 'Bosnia e Hercegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Bélxica', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benín', + 'BL' => 'San Bartolomé', + 'BM' => 'Bermudas', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brasil', + 'BS' => 'Bahamas', + 'BT' => 'Bután', + 'BV' => 'Illa Bouvet', + 'BW' => 'Botswana', + 'BY' => 'Bielorrusia', + 'BZ' => 'Belice', + 'CA' => 'Canadá', + 'CC' => 'Illas Cocos (Keeling)', + 'CD' => 'Congo, República Democrática do', + 'CF' => 'República Centro Africana', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Chipre', + 'CZ' => 'República Checa', + 'DE' => 'Alemaña', + 'DJ' => 'Djibuti', + 'DK' => 'Dinamarca', + 'DM' => 'Dominica', + 'DO' => 'República Dominicana', + 'DZ' => 'Alxeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Exipto', + 'EH' => 'O Sáhara Occidental', + 'ER' => 'Eritrea', + 'ES' => 'España', + 'ET' => 'Etiopía', + 'FI' => 'Finlandia', + 'FJ' => 'Fidji', + 'FK' => 'Illas Malvinas', + 'FM' => 'Estados Federados da Micronesia', + 'FO' => 'Illas Feroe', + 'FR' => 'Francia', + 'GA' => 'Gabón', + 'GB' => 'Reino Unido', + 'GD' => 'Granada', + 'GE' => 'Xeorxia', + 'GF' => 'Güiana Francesa', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Xibraltar', + 'GL' => 'Groenlandia', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadalupe', + 'GQ' => 'Guinea Ecuatorial', + 'GR' => 'Grecia', + 'GS' => 'Xeorxia do Sur e Islas Sandwich do Sur', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bisau', + 'GY' => 'Güiana', + 'HK' => 'Hong Kong', + 'HM' => 'Illas Heard e McDonald', + 'HN' => 'Honduras', + 'HR' => 'Croacia', + 'HT' => 'Haití', + 'HU' => 'Hungría', + 'ID' => 'Indonesia', + 'IE' => 'Irlanda', + 'IL' => 'Israel', + 'IM' => 'Illa de Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldivas', + 'MW' => 'Malaui', + 'MX' => 'México', + 'MY' => 'Malaisia', + 'MZ' => 'Mozambique', + 'N/A' => 'Sen correspondencia (IP local…)', + 'NA' => 'Namibia', + 'NC' => 'Nova Caledonia', + 'NE' => 'Níxer', + 'NF' => 'Illa Norfolk', + 'NG' => 'Nixeria', + 'NI' => 'Nicaragua', + 'NL' => 'Países Baixos', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nova Zelandia', + 'OM' => 'Omán', + 'PA' => 'Panamá', + 'PE' => 'Perú', + 'PF' => 'Polinesia francesa', + 'PG' => 'Papúa Nova Guinea', + 'PH' => 'Filipinas', + 'PK' => 'Paquistán', + 'PL' => 'Polonia', + 'PM' => 'San Pedro e Miguelón', + 'PN' => 'Pitcairn', + 'PR' => 'Porto Rico', + 'PS' => 'Estado de Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguai', + 'QA' => 'Catar', + 'RE' => 'Reunión', + 'RO' => 'Romanía', + 'RS' => 'Serbia', + 'RU' => 'Federación Rusa', + 'RW' => 'Ruanda', + 'SA' => 'Arabia Saudita', + 'SB' => 'Illas Salomón', + 'SC' => 'Seixeles', + 'SD' => 'Sudán', + 'SE' => 'Suecia', + 'SG' => 'Singapur', + 'SH' => 'Santa Helena, Ascensión e Tristán da Cunha', + 'SI' => 'Eslovenia', + 'SJ' => 'Svalbard e Jan Mayen', + 'SK' => 'Eslovaquia', + 'SL' => 'Serra Leoa', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/gl/Dashboard.php b/modules/Admin/Language/gl/Dashboard.php new file mode 100644 index 00000000..696e934e --- /dev/null +++ b/modules/Admin/Language/gl/Dashboard.php @@ -0,0 +1,28 @@ + 'Taboleiro de administración', + 'welcome_message' => 'Ben vida á zona de administración!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Sen podcasts publicados', + 'last_published' => 'Última publicación o {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodios', + 'not_found' => 'Sen episodios publicados', + 'last_published' => 'Última publicación o {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Almacenaxe', + 'subtitle' => '{totalUploaded} de {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/gl/Episode.php b/modules/Admin/Language/gl/Episode.php new file mode 100644 index 00000000..00919216 --- /dev/null +++ b/modules/Admin/Language/gl/Episode.php @@ -0,0 +1,225 @@ + 'Tempada {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episodio {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Tempada {seasonNumber} episodio {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comentario} + other {# comentarios} + }', + 'all_podcast_episodes' => 'Tódolos episodios do podcast', + 'back_to_podcast' => 'Volver ao podcast', + 'edit' => 'Editar', + 'preview' => 'Vista previa', + 'publish' => 'Publicar', + 'publish_edit' => 'Editar publicación', + 'publish_date_edit' => 'Editar data de publicación', + 'unpublish' => 'Retirar publicación', + 'publish_error' => 'O episodio xa está publicado.', + 'publish_edit_error' => 'O episodio xa está publicado.', + 'publish_cancel_error' => 'O episodio xa está publicado.', + 'publish_date_edit_error' => 'O episodio aínda non se publicou, non podes editar a súa data de publicación.', + 'publish_date_edit_future_error' => 'A data de publicación do episodio só pode establecerse nun momento do pasado! Se queres reprogramalo, primeiro retira a súa publicación.', + 'publish_date_edit_success' => 'Actualizada correctamente a data de publicación do episodio!', + 'unpublish_error' => 'O episodio non foi publicado.', + 'delete' => 'Eliminar', + 'go_to_page' => 'Ir á páxina', + 'create' => 'Engadir un episodio', + 'publication_status' => [ + 'published' => 'Publicado', + 'with_podcast' => 'Publicado', + 'scheduled' => 'Programado', + 'not_published' => 'Sen publicar', + ], + 'with_podcast_hint' => 'Para ser publicado ao mesmo tempo que o podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Buscar un episodio', + 'clear' => 'Limpar busca', + 'submit' => 'Buscar', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episodio} + other {# episodios} + }', + 'episode' => 'Episodio', + 'visibility' => 'Visibilidade', + 'downloads' => 'Descargas', + 'comments' => 'Comentarios', + 'actions' => 'Accións', + ], + 'messages' => [ + 'createSuccess' => 'Episodio creado correctamente!', + 'editSuccess' => 'Episodio actualizado correctamente!', + 'publishSuccess' => '{publication_status, select, + published {Episodio publicado correctamente!} + scheduled {Programación correcta para o episodio!} + with_podcast {Este episodio vaise publicar ao mesmo tempo que o podcast.} + other {Este episodio non foi publicado.} + }', + 'publishCancelSuccess' => 'Cancelouse correctamente a publicación do episodio!', + 'unpublishBeforeDeleteTip' => 'Tes que retirar a publicación do episodio antes de eliminalo.', + 'scheduleDateError' => 'Debes establecer a data de publicación!', + 'deletePublishedEpisodeError' => 'Retira a publicación do episodio antes de eliminalo.', + 'deleteSuccess' => 'Episodio eliminado correctamente!', + 'deleteError' => 'Fallou a eliminación {type, select, + transcript {da transcrición} + chapters {dos capítulos} + image {da imaxe} + audio {do audio} + other {do multimedia} + } do episodio.', + 'deleteFileError' => 'Fallou a eliminación do ficheiro {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } {file_key}. Deberías eliminalo a man do disco.', + 'sameSlugError' => 'Xa existe un episodio co id de url elexido.', + ], + 'form' => [ + 'file_size_error' => + 'O ficheiro é demasiado grande! O máximo é {0}. Aumenta os valores de `memory_limit`, `upload_max_filesize` e `post_max_size` no ficheiro de configuración php e reinicia o servidor web.', + 'audio_file' => 'Ficheiro de son', + 'audio_file_hint' => 'Elixe un ficheiro .mp3 ou un .m4a de audio.', + 'info_section_title' => 'Info do episodio', + 'cover' => 'Portada do episodio', + 'cover_hint' => + 'Se non estableces unha portada usarase a portada do podcast no seu lugar.', + 'cover_size_hint' => 'A portada ten que ser cadrada e como mínimo de 1400px de alto e ancho.', + 'title' => 'Título', + 'title_hint' => + 'Debe conter un nome de episodio claro e conciso. Non indiques aquí a tempada ou número de episodio.', + 'permalink' => 'Ligazón permanente', + 'season_number' => 'Tempada', + 'episode_number' => 'Episodio', + 'type' => [ + 'label' => 'Tipo', + 'full' => 'Completo', + 'full_hint' => 'Contido completo (o episodio)', + 'trailer' => 'Avance', + 'trailer_hint' => 'Peza curta de carácter promocional que representa unha vista previa do programa actual', + 'bonus' => 'Extra', + 'bonus_hint' => 'Contido extra para o programa (por exemplo, info sobre a elaboración ou conversa casual cos participantes) ou contido promocional de outras creadoras', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episodio dispoñible só para subscricións premium', + 'parental_advisory' => [ + 'label' => 'Aviso sobre o contido', + 'hint' => 'Contén o episodio elementos explícitos?', + 'undefined' => 'non definido', + 'clean' => 'Limpo', + 'explicit' => 'Explícito', + ], + 'show_notes_section_title' => 'Mostrar notas', + 'show_notes_section_subtitle' => + 'Ata 4000 caracteres, mantén a concisión e claridade. As notas do episodio axudan a que pontenciais oíntes atopen o programa.', + 'description' => 'Descrición', + 'description_footer' => 'Nota ao pé descritiva', + 'description_footer_hint' => + 'Este texto engádese ao final da descrición de cada episodio, é un bo lugar para engadir por exemplo ligazóns a medios sociais.', + 'additional_files_section_title' => 'Ficheiros adicionais', + 'additional_files_section_subtitle' => + 'Estos ficheiros poden ser usados por outras plataformas para proporcionar unha mellor experiencia para a túa audiencia. Mira {podcastNamespaceLink} para máis información.', + 'location_section_title' => 'Localización', + 'location_section_subtitle' => 'De qué lugar trata o episodio?', + 'location_name' => 'Nome da localización e enderezo', + 'location_name_hint' => 'Pode ser unha localización real ou ficticia', + 'transcript' => 'Transcrición (subtítulos / texto descritivo)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Descargar transcrición', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'URL remoto da transcrición', + 'transcript_file_delete' => 'Eliminar ficheiro coa transcrición', + 'chapters' => 'Capítulos', + 'chapters_hint' => 'O ficheiro ten que estar no formato JSON de Capítulos.', + 'chapters_download' => 'Descargar capítulos', + 'chapters_file' => 'Ficheiro de capítulos', + 'chapters_remote_url' => 'URL remoto para ficheiro de capítulos', + 'chapters_file_delete' => 'Eliminar ficheiro de capítulos', + 'advanced_section_title' => 'Parámetros Avanzados', + 'advanced_section_subtitle' => + 'Se precisas etiquetas RSS que Castopod non xestiona, establéceas aquí.', + 'custom_rss' => 'Etiquetas RSS personalizadas para o episodio', + 'custom_rss_hint' => 'Esto vai ir incluído na etiqueta ❬item❭.', + 'block' => 'O episodio estará oculto para os catálogos públicos', + 'block_hint' => + 'O estado oculto ou visible: este control evita que o episodio apareza en Apple Podcasts, Google Podcasts, e calquera outra app de terceiros que obteña os programas destos directorios. (Non garantido)', + 'submit_create' => 'Crear episodio', + 'submit_edit' => 'Gardar episodio', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Volver ao taboleiro do episodio', + 'post' => 'Publicación co anuncio', + 'post_hint' => + "Escribe unha mensaxe para anunciar a publicación do episodio. Esta mensaxe será enviada a tódalas túas seguidoras no fediverso e aparecerá na páxina de inicio do teu podcast.", + 'message_placeholder' => 'Escribe a mensaxe…', + 'publication_date' => 'Data de publicación', + 'publication_method' => [ + 'now' => 'Agora', + 'schedule' => 'Programar', + 'with_podcast' => 'Publicar xunto co podcast', + ], + 'scheduled_publication_date' => 'Data da publicación programada', + 'scheduled_publication_date_clear' => 'Limpar data de publicación', + 'scheduled_publication_date_hint' => + 'Podes programar nunha data futura a publicación do episodio. Este campo debe ter formato YYYY-MM-DD HH:mm', + 'submit' => 'Publicar', + 'submit_edit' => 'Editar publicación', + 'cancel_publication' => 'Cancelar publicación', + 'message_warning' => 'Non escribiches unha mensaxe anunciando a publicación!', + 'message_warning_hint' => 'Ao escribir unha mensaxe aumentas o alcance social, resultando en maior visibilidade para o teu episodio.', + 'message_warning_submit' => 'Publicar igualmente', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nova data de publicación', + 'new_publication_date_hint' => 'Ten que ser unha data do pasado.', + 'submit' => 'Editar data de publicación', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Retirando o episodio eliminarás tódolos comentarios e publicacións asociadas con el e tamén o eliminarás da fonte RSS do podcast.", + 'understand' => 'Enténdoo e quero retirar o episodio', + 'submit' => 'Retirar episodio', + ], + 'delete_form' => [ + 'disclaimer' => + "Eliminando o episodio eliminarás tódolos ficheiros multimedia, comentarios, clips de vídeo e extractos de son asociados a el.", + 'understand' => 'Enténdoo e quero eliminar o episodio', + 'submit' => 'Eliminar', + ], + 'embed' => [ + 'title' => 'Reprodutor para incluír', + 'label' => + 'Elixe a cor do decorado, copia o código para o reprodutor a incluir e pégao no teu sitio web.', + 'clipboard_iframe' => 'Copia o reprodutor ao portapapeis', + 'clipboard_url' => 'Copiar enderezo ao portapapeis', + 'dark' => 'Escuro', + 'dark-transparent' => 'Escuro transparente', + 'light' => 'Claro', + 'light-transparent' => 'Claro transparente', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'modo borrador', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Vista previa', + ], +]; diff --git a/modules/Admin/Language/gl/EpisodeNavigation.php b/modules/Admin/Language/gl/EpisodeNavigation.php new file mode 100644 index 00000000..1a120a5a --- /dev/null +++ b/modules/Admin/Language/gl/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Ver páxina do episodio', + 'dashboard' => 'Taboleiro do episodio', + 'episode-view' => 'Inicio', + 'episode-edit' => 'Editar episodio', + 'episode-persons-manage' => 'Xestionar persoas', + 'embed-add' => 'Reprodutor para incluír', + 'clips' => 'Recortes', + 'video-clips-list' => 'Recortes de vídeo', + 'video-clips-create' => 'Novo recorte de vídeo', + 'soundbites-list' => 'Anaquiños', + 'soundbites-create' => 'Novo anaquiño', +]; diff --git a/modules/Admin/Language/gl/Fediverse.php b/modules/Admin/Language/gl/Fediverse.php new file mode 100644 index 00000000..6402a7e4 --- /dev/null +++ b/modules/Admin/Language/gl/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Non se atopou a conta!', + 'blockActorSuccess' => '{actor} foi bloqueado!', + 'unblockActorSuccess' => '{actor} foi desbloqueado!', + 'blockDomainSuccess' => '{domain} foi bloqueado!', + 'unblockDomainSuccess' => '{domain} foi desbloqueado!', + ], + 'blocked_actors' => 'Contas bloqueadas', + 'blocked_domains' => 'Dominios bloqueados', + 'block_lists_form' => [ + 'handle' => 'Alcume da conta', + 'handle_hint' => 'Escribe a conta @usuaria@dominio.', + 'domain' => 'Nome de dominio', + 'submit' => 'Bloqueo!', + ], + 'list' => [ + 'actor' => 'Conta', + 'domain' => 'Nome de dominio', + 'unblock' => 'Desbloquear', + ], +]; diff --git a/modules/Admin/Language/gl/Home.php b/modules/Admin/Language/gl/Home.php new file mode 100644 index 00000000..29edd1c7 --- /dev/null +++ b/modules/Admin/Language/gl/Home.php @@ -0,0 +1,14 @@ + 'Tódolos podcast', + 'no_podcast' => 'Non se atopan podcast', +]; diff --git a/modules/Admin/Language/gl/Install.php b/modules/Admin/Language/gl/Install.php new file mode 100644 index 00000000..c740ba7c --- /dev/null +++ b/modules/Admin/Language/gl/Install.php @@ -0,0 +1,61 @@ + 'Configuración manual', + 'manual_config_subtitle' => + 'Crear un ficheiro `.env` cos teus axustes e actualizar a páxina para continuar coa instalación.', + 'form' => [ + 'instance_config' => 'Configuración da instancia', + 'hostname' => 'Servidor', + 'media_base_url' => 'URL base do multimedia', + 'media_base_url_hint' => + 'Se usas unha CDN e/ou un servizo externo de análise, debes indicalo aquí.', + 'admin_gateway' => 'Pasarela de administración', + 'admin_gateway_hint' => + 'A ruta para acceder á área de administración (ex. https://exemplo.com/cp-admin). Por defecto establécese cp-admin, recomendámosche cambialo por razóns de seguridade.', + 'auth_gateway' => 'Pasarela de autenticación', + 'auth_gateway_hint' => + 'A ruta para acceder á páxina de autenticación (ex. https://exemplo.com/cp-auth). Por defecto establécese como cp-auth, pero recomendámosche cambialo por razóns de seguridade.', + 'database_config' => 'Configuración da base de datos', + 'database_config_hint' => + 'Castopod precisa conectar coa túa base de datos MySQL (ou MariaDB). Se non tes esta información, contacta coa administración do teu servidor.', + 'db_hostname' => 'Servidor da base de datos', + 'db_name' => 'Nome da base de datos', + 'db_username' => 'Usuaria da base de datos', + 'db_password' => 'Contrasinal da base de datos', + 'db_prefix' => 'Prefix da base de datos', + 'db_prefix_hint' => + "O prefix dos nomes das táboas Castopod, déixao como está se non sabes o significa.", + 'cache_config' => 'Configuración da caché', + 'cache_config_hint' => + 'Elixe o xestor da caché preferido. Deixa o valor por defecto se non sabes o que significa.', + 'cache_handler' => 'Xestor da cache', + 'cacheHandlerOptions' => [ + 'file' => 'Ficheiro', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Seguinte', + 'submit' => 'Rematar instalación', + 'create_superadmin' => 'Crea a conta de superadministración', + 'email' => 'Email', + 'username' => 'Identificador', + 'password' => 'Contrasinal', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'A conta de superadministración creouse correctamente. Accede para comezar a publicar!', + 'databaseConnectError' => + 'Castopod non pode conectar coa base de datos. Edita a configuración da base de datos e inténtao outra vez.', + 'writeError' => + "Non se puido crear/escribir o ficheiro `.env`. Tes que crealo manualmente seguindo o modelo `.env.example` incluído no paquete Castopod.", + ], +]; diff --git a/modules/Admin/Language/gl/Navigation.php b/modules/Admin/Language/gl/Navigation.php new file mode 100644 index 00000000..eddbd6cb --- /dev/null +++ b/modules/Admin/Language/gl/Navigation.php @@ -0,0 +1,44 @@ + 'Activar barra lateral', + 'go_to_website' => 'Ir ao sitio web', + 'go_to_admin' => 'Ir á administración', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Taboleiro', + 'admin' => 'Inicio', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Tódolos podcast', + 'podcast-create' => 'Novo podcast', + 'all-podcast-imports' => 'Todas as importancións de Podcast', + 'podcast-imports-add' => 'Importar un podcast', + 'persons' => 'Persoas', + 'person-list' => 'Tódalas persoas', + 'person-create' => 'Nova persoa', + 'fediverse' => 'Fediverso', + 'fediverse-blocked-actors' => 'Contas bloqueadas', + 'fediverse-blocked-domains' => 'Dominios bloqueados', + 'users' => 'Usuarias', + 'user-list' => 'Tódalas usuarias', + 'user-create' => 'Nova usuaria', + 'pages' => 'Páxinas', + 'page-list' => 'Tódalas páxinas', + 'page-create' => 'Nova páxina', + 'settings' => 'Axustes', + 'settings-general' => 'Xeral', + 'settings-theme' => 'Decorado', + 'admin-about' => 'Acerca de', + 'account' => [ + 'my-account' => 'A miña conta', + 'change-password' => 'Cambiar contrasinal', + 'logout' => 'Saír', + ], +]; diff --git a/modules/Admin/Language/gl/Notifications.php b/modules/Admin/Language/gl/Notifications.php new file mode 100644 index 00000000..b2b82a68 --- /dev/null +++ b/modules/Admin/Language/gl/Notifications.php @@ -0,0 +1,19 @@ + 'Notificacións', + 'reply' => '{actor_username} respondeu á túa publicación', + 'favourite' => '{actor_username} fixo favorita a túa publicación', + 'reblog' => '{actor_username} compartiu a túa publicación', + 'follow' => '{actor_username} comezou a seguirte', + 'no_notifications' => 'Sen notificacións', + 'mark_all_as_read' => 'Marcar todo como lido', +]; diff --git a/modules/Admin/Language/gl/Page.php b/modules/Admin/Language/gl/Page.php new file mode 100644 index 00000000..15dbde00 --- /dev/null +++ b/modules/Admin/Language/gl/Page.php @@ -0,0 +1,30 @@ + 'Volver ao inicio', + 'page' => 'Páxina', + 'all_pages' => 'Tódalas páxinas', + 'create' => 'Nova páxina', + 'go_to_page' => 'Ir á páxina', + 'edit' => 'Editar páxina', + 'delete' => 'Eliminar páxina', + 'form' => [ + 'title' => 'Título', + 'permalink' => 'Ligazón permanente', + 'content' => 'Contido', + 'submit_create' => 'Crear páxina', + 'submit_edit' => 'Gardar', + ], + 'messages' => [ + 'createSuccess' => 'Creouse correctamente a páxina "{pageTitle}"!', + 'editSuccess' => 'Actualizouse correctamente a páxina!', + ], +]; diff --git a/modules/Admin/Language/gl/Pager.php b/modules/Admin/Language/gl/Pager.php new file mode 100644 index 00000000..390b2e72 --- /dev/null +++ b/modules/Admin/Language/gl/Pager.php @@ -0,0 +1,21 @@ + 'Navegador de páxinas', + 'first' => 'Primeira', + 'previous' => 'Anterior', + 'next' => 'Seguinte', + 'last' => 'Última', + 'older' => 'Máis antiga', + 'newer' => 'Máis nova', + 'invalidTemplate' => '{0} non é un modelo para páxinas válido.', + 'invalidPaginationGroup' => '{0} non é un grupo de navegación de páxinas válido.', +]; diff --git a/modules/Admin/Language/gl/Person.php b/modules/Admin/Language/gl/Person.php new file mode 100644 index 00000000..b8d5bd5d --- /dev/null +++ b/modules/Admin/Language/gl/Person.php @@ -0,0 +1,65 @@ + 'Persoas', + 'all_persons' => 'Tódalas persoas', + 'no_person' => 'Non hai ninguén!', + 'create' => 'Crear unha persoa', + 'view' => 'Ver persoa', + 'edit' => 'Editar persoa', + 'delete' => 'Eliminar persoa', + 'messages' => [ + 'createSuccess' => 'Persoa creada correctamente!', + 'editSuccess' => 'Persoa actualizada correctamente!', + 'deleteSuccess' => 'Eliminouse a Persoa!', + ], + 'form' => [ + 'avatar' => 'Imaxe de perfil', + 'avatar_size_hint' => + 'A imaxe do perfil ten que ser cadrada e como pouco de 400px de alto e ancho.', + 'full_name' => 'Nome completo', + 'full_name_hint' => 'Este é o nome completo ou alias da persoa.', + 'unique_name' => 'Nome único', + 'unique_name_hint' => 'Usado nos URLs', + 'information_url' => 'URL de información', + 'information_url_hint' => + 'Url a un recurso con información relevante sobre a persoa, como unha web ou plataforma de terceiras partes.', + 'submit_create' => 'Crear persoa', + 'submit_edit' => 'Gardar persoa', + ], + 'podcast_form' => [ + 'title' => 'Xestionar persoas', + 'add_section_title' => 'Engadir persoas a este podcast', + 'add_section_subtitle' => 'Podes elexir varias persoas e roles.', + 'persons' => 'Persoas', + 'persons_hint' => + 'Podes elexir unha ou varias persoas cos mesmos roles. Precisas crear primeiro as persoas.', + 'roles' => 'Roles', + 'roles_hint' => + 'Podes seleccionar un, ningún ou varios roles para a persoa.', + 'submit_add' => 'Engadir persoa(s)', + 'remove' => 'Eliminar', + ], + 'episode_form' => [ + 'title' => 'Xestionar persoas', + 'add_section_title' => 'Engdir persoas a este episodio', + 'add_section_subtitle' => 'Podes elexir varias persoas e roles.', + 'persons' => 'Persoas', + 'persons_hint' => + 'Podes elexir unha ou varias persoas cos mesmos roles. Primeiro tes que crear as persoas.', + 'roles' => 'Roles', + 'roles_hint' => + 'Podes seleccionar un, ningún ou varios roles para unha persoa.', + 'submit_add' => 'Engadir persoa(s)', + 'remove' => 'Eliminar', + ], + 'credits' => 'Créditos', +]; diff --git a/modules/Admin/Language/gl/Platforms.php b/modules/Admin/Language/gl/Platforms.php new file mode 100644 index 00000000..9d34da3a --- /dev/null +++ b/modules/Admin/Language/gl/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Plataformas de podcast', + 'social' => 'Redes sociais', + 'funding' => 'Finanzamento', + ], + 'website' => 'Sitio web', + 'home_url' => 'Ir á web de {platformName}', + 'register' => 'Crear conta', + 'submit_url' => 'Envía o teu podcast en {platformName}', + 'your_link' => 'A túa ligazón', + 'your_id' => [ + 'podcasting' => 'O teu ID', + 'social' => 'O teu ID', + 'funding' => 'O teu CTA', + ], + 'your_cta' => 'Chamar á acción', + 'visible' => 'Mostrar na páxina de inicio do podcast?', + 'on_embed' => 'Mostrar no navegador incrustable?', + 'remove' => 'Eliminar {platformName}', + 'submit' => 'Gardar', + 'messages' => [ + 'updateSuccess' => 'Actualizáronse correctamente as ligazóns á plataforma!', + 'removeLinkSuccess' => 'Eliminouse a ligazón á plataforma.', + 'removeLinkError' => + 'A ligazón á plataforma non se puido eliminar. Inténtao outra vez.', + ], + 'description' => [ + 'podcasting' => 'ID do podcast nesta plataforma', + 'social' => 'ID da conta do podcast nesta plataforma', + 'funding' => 'Mensaxe de convite a realizar acción', + ], +]; diff --git a/modules/Admin/Language/gl/Podcast.php b/modules/Admin/Language/gl/Podcast.php new file mode 100644 index 00000000..baa05597 --- /dev/null +++ b/modules/Admin/Language/gl/Podcast.php @@ -0,0 +1,330 @@ + 'Tódolos podcast', + 'no_podcast' => 'Non se atopan podcast!', + 'create' => 'Crear un podcast', + 'import' => 'Importar podcast', + 'all_imports' => 'Importacións de podcasts', + 'new_episode' => 'Novo Episodio', + 'view' => 'Ver podcast', + 'edit' => 'Editar podcast', + 'publish' => 'Publicar podcast', + 'publish_edit' => 'Editar publicación', + 'delete' => 'Eliminar podcast', + 'see_episodes' => 'Ver episodios', + 'see_contributors' => 'Ver colaboradoras', + 'monetization_other' => 'Outros xeitos', + 'go_to_page' => 'Ir á páxina', + 'latest_episodes' => 'Últimos episodios', + 'see_all_episodes' => 'Ver tódolos episodios', + 'draft' => 'Borrador', + 'messages' => [ + 'createSuccess' => 'Podcast creado correctamente!', + 'editSuccess' => 'Episodio actualizado correctamente!', + 'importSuccess' => 'Episodio importado correctamente!', + 'deleteSuccess' => 'Eliminado o podcast @{podcast_handle}!', + 'deletePodcastMediaError' => 'Fallou a eliminación {type, select, + cover {da portada} + banner {da cabeceira} + other {do multimedia} + } do podcast.', + 'deleteEpisodeMediaError' => 'Fallou a eliminación {type, select, + transcript {da transcrición} + chapters {dos capítulos} + image {da imaxe} + audio {do audio} + other {do multimedia} + } do episodio {episode_slug}.', + 'deletePodcastMediaFolderError' => 'Fallou a eliminación do cartafol {folder_path} co multimedia do podcast. Intenta eliminalo do teu disco de xeito manual.', + 'podcastFeedUpdateSuccess' => 'Actualización correcta: {number_of_new_episodes, plural, + one {# episodio foi engadido} + other {# episodios foron engadidos} + } ao podcast!', + 'podcastFeedUpToDate' => 'O podcast xa está ao día.', + 'publishError' => 'Este podcast ou ben xa foi publicado ou está programada a súa publicación.', + 'publishEditError' => 'Este podcast non ten a publicación programada.', + 'publishCancelSuccess' => 'Cancelouse correctamente a publicación do podcast!', + 'scheduleDateError' => 'Hai que establecer a data da publicación!', + ], + 'form' => [ + 'identity_section_title' => 'Identidade do podcast', + 'identity_section_subtitle' => 'Estes campos permítenche recibir notificacións.', + 'fediverse_section_title' => 'Identidade no fediverso', + + 'cover' => 'Portada do podcast', + 'cover_size_hint' => 'A portada ten que ser cadrada e como mínimo de 1400px de alto e ancho.', + 'banner' => 'Cabeceira do podcast', + 'banner_size_hint' => 'A imaxe de cabeceira debe ter proporción 3:1 e 1500px. como mínimo.', + 'banner_delete' => 'Eliminar cabeceira do podcast', + 'title' => 'Título', + 'handle' => 'Identificador', + 'handle_hint' => + 'Utilizado para identificar o podcast. Permítense maiúsculas, minúsculas, números e trazo baixo.', + 'type' => [ + 'label' => 'Tipo', + 'episodic' => 'Recurrente', + 'episodic_hint' => 'Se os episodios non teñen unha orde predeterminada para ser escoitados. Os novos episodios serán mostrados antes.', + 'serial' => 'Serie', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Descrición', + 'classification_section_title' => 'Clasificación', + 'classification_section_subtitle' => + 'Estos campos terán impacto na túa audiencia e competencia.', + 'language' => 'Idioma', + 'category' => 'Categoría', + 'category_placeholder' => 'Elixe unha categoría…', + 'other_categories' => 'Outras categorías', + 'parental_advisory' => [ + 'label' => 'Aviso parental', + 'hint' => 'Inclúe contidos explícitos?', + 'undefined' => 'sen definir', + 'clean' => 'Aceptable', + 'explicit' => 'Explícito', + ], + 'author_section_title' => 'Autoría', + 'author_section_subtitle' => 'Quen xestiona o podcast?', + 'owner_name' => 'Nome da propietaria', + 'owner_name_hint' => + 'Só para uso administrativo. Visible na fonte RSS pública.', + 'owner_email' => 'Correo da propietaria', + 'owner_email_hint' => + 'Será utilizado pola maioría das plataformas para verificar a propiedade do podcast. Visible na fonte RSS pública.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Editorial', + 'publisher_hint' => + 'O grupo responsable da creación do programa. Normalmente refírese á empresa nai ou rede do podcast. O campo a veces etiquétase como \'Autor\'.', + 'copyright' => 'Dereitos', + 'location_section_title' => 'Localización', + 'location_section_subtitle' => 'De qué lugar trata o podcast?', + 'location_name' => 'Nome do lugar ou enderezo', + 'location_name_hint' => 'Pode ser un lugar real ou ficticio', + 'monetization_section_title' => 'Monetización', + 'monetization_section_subtitle' => + 'Obter cartos grazas á túa audiencia.', + 'premium' => 'Premium', + 'premium_by_default' => 'Os episodios estableceranse por defecto como premium', + 'premium_by_default_hint' => 'Os episodios vanse marcar por defecto como premium. Podes igualmente elexir algúns episodios, mostras ou extras como públicos.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/gl/PodcastNavigation.php b/modules/Admin/Language/gl/PodcastNavigation.php new file mode 100644 index 00000000..c47b51dc --- /dev/null +++ b/modules/Admin/Language/gl/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Ir á páxina do podcast', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Taboleiro do podcast', + 'podcast-view' => 'Inicio', + 'podcast-edit' => 'Editar podcast', + 'podcast-persons-manage' => 'Xestionar persoas', + 'podcast-imports' => 'Importacións de podcasts', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodios', + 'episode-list' => 'Todos os episodios', + 'episode-create' => 'Novo episodio', + 'analytics' => 'Análise', + 'podcast-analytics' => 'Ollada sobre a audiencia', + 'podcast-analytics-webpages' => 'Visitas á páxina web', + 'podcast-analytics-locations' => 'Localizacións', + 'podcast-analytics-unique-listeners' => 'Oíntes únicos', + 'podcast-analytics-players' => 'Reprodutores', + 'podcast-analytics-listening-time' => 'Tempo de escoita', + 'podcast-analytics-time-periods' => 'Período de tempo', + 'monetization' => 'Monetization', + 'subscription-list' => 'Todas as subscricións', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contribúen', + 'contributor-list' => 'Todas as contribucións', + 'contributor-add' => 'Engadir colaboración', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Redes sociais', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/gl/Settings.php b/modules/Admin/Language/gl/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/gl/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/gl/Soundbite.php b/modules/Admin/Language/gl/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/gl/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/gl/Validation.php b/modules/Admin/Language/gl/Validation.php new file mode 100644 index 00000000..42d6a672 --- /dev/null +++ b/modules/Admin/Language/gl/Validation.php @@ -0,0 +1,17 @@ + + 'ou ben {field} non é unha imaxe ou non é suficientemente alta ou ancha.', + 'is_image_ratio' => + 'ou ben {field} non é unha imaxe ou non ten proporcións axeitadas.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/gl/VideoClip.php b/modules/Admin/Language/gl/VideoClip.php new file mode 100644 index 00000000..bd5764e8 --- /dev/null +++ b/modules/Admin/Language/gl/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Recortes de vídeo', + 'status' => [ + 'label' => 'Estado', + 'queued' => 'na cola', + 'queued_hint' => 'Agardando para procesar o vídeo.', + 'pending' => 'pendente', + 'pending_hint' => 'En breve será creado o vídeo.', + 'running' => 'en execución', + 'running_hint' => 'Estase creando o vídeo.', + 'failed' => 'fallou', + 'failed_hint' => 'Non se puido crear o vídeo: fallou o script.', + 'passed' => 'correcto', + 'passed_hint' => 'Creouse correctamente o vídeo!', + ], + 'clip' => 'Recorte', + 'duration' => 'Duración da tarefa', + ], + 'title' => 'Recorte de vídeo: {videoClipLabel}', + 'download_clip' => 'Descargar vídeo', + 'create' => 'Novo recorte de vídeo', + 'go_to_page' => 'Ir á páxina do vídeo', + 'retry' => 'Volver a intentar a xeración', + 'delete' => 'Eliminar recorte', + 'logs' => 'Rexistros da tarefa', + 'messages' => [ + 'alreadyExistingError' => 'O recorte de vídeo que intentas crear xa existe!', + 'addToQueueSuccess' => 'Engadiuse o recorte de vídeo á cola, agardando a ser creado!', + 'deleteSuccess' => 'Eliminouse correctamente o recorte de vídeo!', + ], + 'format' => [ + 'landscape' => 'Horizontal', + 'portrait' => 'Vertical', + 'squared' => 'Cadrado', + ], + 'form' => [ + 'title' => 'Novo recorte de vídeo', + 'params_section_title' => 'Parámetros do vídeo', + 'clip_title' => 'Título do vídeo', + 'format' => [ + 'label' => 'Elixe o formato', + 'landscape_hint' => 'Cunha razón 16:9, os vídeos horizontais quedan ben en PeerTube, Youtube e Vimeo.', + 'portrait_hint' => 'Cunha razón 9:16, os vídeos verticais lucen ben en TikTok, curtas de Youtube e historias de Instagram.', + 'squared_hint' => 'Cunha razón 1:1, os vídeos cadrados quedan ben en Mastodon, Facebook, Twitter e LinkedIn.', + ], + 'theme' => 'Elixe un decorado', + 'start_time' => 'Comezar en', + 'duration' => 'Duración', + 'trim_start' => 'Axustar inicio', + 'trim_end' => 'Axustar final', + 'submit' => 'Crear recorte de vídeo', + ], + 'requirements' => [ + 'title' => 'Falta de requisitos', + 'missing' => 'Non cumpres certos requisitos. Comproba que engadiches tódolos elementos requeridos para poder crear un vídeo para este episodio!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Biblioteca Freetype para GD', + 'transcript' => 'Ficheiro Transcript (.srt)', + ], +]; diff --git a/modules/Admin/Language/id/AboutCastopod.php b/modules/Admin/Language/id/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/id/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/id/Breadcrumb.php b/modules/Admin/Language/id/Breadcrumb.php new file mode 100644 index 00000000..4e6f3a8e --- /dev/null +++ b/modules/Admin/Language/id/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'pengguna', + 'my-account' => 'akun saya', + 'change-password' => 'ubah kata sandi', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analitik', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/id/Charts.php b/modules/Admin/Language/id/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/id/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/id/Common.php b/modules/Admin/Language/id/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/id/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/id/Countries.php b/modules/Admin/Language/id/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/id/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/id/Dashboard.php b/modules/Admin/Language/id/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/id/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/id/Episode.php b/modules/Admin/Language/id/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/id/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/id/EpisodeNavigation.php b/modules/Admin/Language/id/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/id/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/id/Fediverse.php b/modules/Admin/Language/id/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/id/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/id/Home.php b/modules/Admin/Language/id/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/id/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/id/Install.php b/modules/Admin/Language/id/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/id/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/id/Navigation.php b/modules/Admin/Language/id/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/id/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/id/Notifications.php b/modules/Admin/Language/id/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/id/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/id/Page.php b/modules/Admin/Language/id/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/id/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/id/Pager.php b/modules/Admin/Language/id/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/id/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/id/Person.php b/modules/Admin/Language/id/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/id/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/id/Platforms.php b/modules/Admin/Language/id/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/id/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/id/Podcast.php b/modules/Admin/Language/id/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/id/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/id/PodcastNavigation.php b/modules/Admin/Language/id/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/id/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/id/Settings.php b/modules/Admin/Language/id/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/id/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/id/Soundbite.php b/modules/Admin/Language/id/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/id/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/id/Validation.php b/modules/Admin/Language/id/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/id/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/id/VideoClip.php b/modules/Admin/Language/id/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/id/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/it/AboutCastopod.php b/modules/Admin/Language/it/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/it/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/it/Breadcrumb.php b/modules/Admin/Language/it/Breadcrumb.php new file mode 100644 index 00000000..7c492350 --- /dev/null +++ b/modules/Admin/Language/it/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodi', + 'subscriptions' => 'sottoscrizioni', + 'contributors' => 'collaboratori', + 'pages' => 'pagine', + 'settings' => 'impostazioni', + 'theme' => 'tema', + 'about' => 'about', + 'add' => 'aggiungi', + 'new' => 'nuovo', + 'edit' => 'modifica', + 'persons' => 'persone', + 'publish' => 'pubblica', + 'publish-edit' => 'modifica pubblicazione', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'annulla pubblicazione', + 'delete' => 'elimina', + 'remove' => 'remove', + 'fediverse' => 'fediverso', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'utenti', + 'my-account' => 'il mio profilo', + 'change-password' => 'cambia la password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'piattaforme', + 'social' => 'social networks', + 'funding' => 'finanziamento', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'posizioni', + 'webpages' => 'pagine web', + 'unique-listeners' => 'ascoltatori unici', + 'players' => 'partecipanti', + 'listening-time' => 'tempo di ascolto', + 'time-periods' => 'periodo di tempo', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'player incorporabile', + 'notifications' => 'notifiche', + 'suspend' => 'sospendi', +]; diff --git a/modules/Admin/Language/it/Charts.php b/modules/Admin/Language/it/Charts.php new file mode 100644 index 00000000..88455fc2 --- /dev/null +++ b/modules/Admin/Language/it/Charts.php @@ -0,0 +1,41 @@ + 'Episodi scaricati per servizio (settimana passata)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/it/Common.php b/modules/Admin/Language/it/Common.php new file mode 100644 index 00000000..82ad7a8c --- /dev/null +++ b/modules/Admin/Language/it/Common.php @@ -0,0 +1,52 @@ + 'Si', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'Nessun dato trovato!', + 'close' => 'Chiudi', + 'edit' => 'Modifica', + 'copy' => 'Copia', + 'copied' => 'Copiato!', + 'home' => 'Home', + 'explicit' => 'Esplicito', + 'powered_by' => 'Fornito da {castopod}', + 'actions' => 'Azioni', + 'pageInfo' => 'Pagina {currentPage} di {pageCount}', + 'go_back' => 'Torna indietro', + 'forms' => [ + 'editor' => [ + 'write' => 'Scrivi', + 'preview' => 'Anteprima', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Premi per selezionare', + 'loadingText' => 'Caricamento…', + 'noResultsText' => 'Nessun risultato trovato', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Impossibile aggiungere ulteriori elementi', + ], + 'upload_file' => 'Carica un file', + 'remote_url' => 'URL remoto', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Riproduci', + 'playing' => 'In riproduzione', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Scegli come interagire', + 'view' => 'Visualizza', +]; diff --git a/modules/Admin/Language/it/Countries.php b/modules/Admin/Language/it/Countries.php new file mode 100644 index 00000000..185d3c37 --- /dev/null +++ b/modules/Admin/Language/it/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emirati Arabi Uniti', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua e Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antartide', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Isole Åland', + 'AZ' => 'Azerbaigian', + 'BA' => 'Bosnia-Erzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgio', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Sultanato del Brunei', + 'BO' => 'Bolivia, Stato Plurinazionale di', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brasile', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Bielorussia', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Isole Cocos (Keeling)', + 'CD' => 'Repubblica Democratica del Congo', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Svizzera', + 'CI' => "Costa d'Avorio", + 'CK' => 'Cook Islands', + 'CL' => 'Cile', + 'CM' => 'Camerun', + 'CN' => 'Cina', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Capo Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cipro', + 'CZ' => 'Repubblica Ceca', + 'DE' => 'Germania', + 'DJ' => 'Djibouti', + 'DK' => 'Danimarca', + 'DM' => 'Dominica', + 'DO' => 'Repubblica Domenicana', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egitto', + 'EH' => 'Sahara occidentale', + 'ER' => 'Eritrea', + 'ES' => 'Spagna', + 'ET' => 'Etiopia', + 'FI' => 'Finlandia', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'Francia', + 'GA' => 'Gabon', + 'GB' => 'Regno Unito', + 'GD' => 'Granada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenlandia', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Corea del Sud (Repubblica di Corea)', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakistan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Libano', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lituania', + 'LU' => 'Luxembourg', + 'LV' => 'Lettonia', + 'LY' => 'Libya', + 'MA' => 'Marocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Paesi Bassi', + 'NO' => 'Norvegia', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portogallo', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'Stati Uniti d\'America', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/it/Dashboard.php b/modules/Admin/Language/it/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/it/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/it/Episode.php b/modules/Admin/Language/it/Episode.php new file mode 100644 index 00000000..a583463a --- /dev/null +++ b/modules/Admin/Language/it/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'Tutti gli episodi del podcast', + 'back_to_podcast' => 'Torna a podcast', + 'edit' => 'Modifica', + 'preview' => 'Preview', + 'publish' => 'Pubblica', + 'publish_edit' => 'Modifica pubblicazione', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Annulla pubblicazione', + 'publish_error' => 'L\'episodio è già stato pubblicato.', + 'publish_edit_error' => 'L\'episodio è già stato pubblicato.', + 'publish_cancel_error' => 'L\'episodio è già stato pubblicato.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episodio non pubblicato.', + 'delete' => 'Elimina', + 'go_to_page' => 'Vai alla pagina', + 'create' => 'Aggiungi un episodio', + 'publication_status' => [ + 'published' => 'Pubblicato', + 'with_podcast' => 'Pubblicato', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Cerca', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/it/EpisodeNavigation.php b/modules/Admin/Language/it/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/it/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/it/Fediverse.php b/modules/Admin/Language/it/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/it/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/it/Home.php b/modules/Admin/Language/it/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/it/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/it/Install.php b/modules/Admin/Language/it/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/it/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/it/Navigation.php b/modules/Admin/Language/it/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/it/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/it/Notifications.php b/modules/Admin/Language/it/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/it/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/it/Page.php b/modules/Admin/Language/it/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/it/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/it/Pager.php b/modules/Admin/Language/it/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/it/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/it/Person.php b/modules/Admin/Language/it/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/it/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/it/Platforms.php b/modules/Admin/Language/it/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/it/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/it/Podcast.php b/modules/Admin/Language/it/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/it/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/it/PodcastNavigation.php b/modules/Admin/Language/it/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/it/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/it/Settings.php b/modules/Admin/Language/it/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/it/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/it/Soundbite.php b/modules/Admin/Language/it/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/it/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/it/Validation.php b/modules/Admin/Language/it/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/it/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/it/VideoClip.php b/modules/Admin/Language/it/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/it/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/ja/AboutCastopod.php b/modules/Admin/Language/ja/AboutCastopod.php new file mode 100644 index 00000000..16c3c2b2 --- /dev/null +++ b/modules/Admin/Language/ja/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Castopodについて', + 'host_name' => 'ホスト名', + 'version' => 'Castopodバージョン', + 'php_version' => 'PHPバージョン', + 'os' => '(OS) オペレーティング システム', + 'languages' => '言語', + 'update_database' => 'データベースを更新', + 'messages' => [ + 'databaseUpdateSuccess' => 'データベースは最新です', + ], +]; diff --git a/modules/Admin/Language/ja/Breadcrumb.php b/modules/Admin/Language/ja/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/ja/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/ja/Charts.php b/modules/Admin/Language/ja/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/ja/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/ja/Common.php b/modules/Admin/Language/ja/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/ja/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/ja/Countries.php b/modules/Admin/Language/ja/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/ja/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/ja/Dashboard.php b/modules/Admin/Language/ja/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/ja/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ja/Episode.php b/modules/Admin/Language/ja/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/ja/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ja/EpisodeNavigation.php b/modules/Admin/Language/ja/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/ja/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/ja/Fediverse.php b/modules/Admin/Language/ja/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/ja/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/ja/Home.php b/modules/Admin/Language/ja/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/ja/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/ja/Install.php b/modules/Admin/Language/ja/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/ja/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/ja/Navigation.php b/modules/Admin/Language/ja/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/ja/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/ja/Notifications.php b/modules/Admin/Language/ja/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/ja/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/ja/Page.php b/modules/Admin/Language/ja/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/ja/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/ja/Pager.php b/modules/Admin/Language/ja/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/ja/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/ja/Person.php b/modules/Admin/Language/ja/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/ja/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/ja/Platforms.php b/modules/Admin/Language/ja/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/ja/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/ja/Podcast.php b/modules/Admin/Language/ja/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/ja/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/ja/PodcastNavigation.php b/modules/Admin/Language/ja/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/ja/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ja/Settings.php b/modules/Admin/Language/ja/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/ja/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/ja/Soundbite.php b/modules/Admin/Language/ja/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/ja/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/ja/Validation.php b/modules/Admin/Language/ja/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/ja/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ja/VideoClip.php b/modules/Admin/Language/ja/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/ja/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/kk/AboutCastopod.php b/modules/Admin/Language/kk/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/kk/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/kk/Breadcrumb.php b/modules/Admin/Language/kk/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/kk/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/kk/Charts.php b/modules/Admin/Language/kk/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/kk/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/kk/Common.php b/modules/Admin/Language/kk/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/kk/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/kk/Countries.php b/modules/Admin/Language/kk/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/kk/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/kk/Dashboard.php b/modules/Admin/Language/kk/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/kk/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/kk/Episode.php b/modules/Admin/Language/kk/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/kk/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/kk/EpisodeNavigation.php b/modules/Admin/Language/kk/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/kk/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/kk/Fediverse.php b/modules/Admin/Language/kk/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/kk/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/kk/Home.php b/modules/Admin/Language/kk/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/kk/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/kk/Install.php b/modules/Admin/Language/kk/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/kk/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/kk/Navigation.php b/modules/Admin/Language/kk/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/kk/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/kk/Notifications.php b/modules/Admin/Language/kk/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/kk/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/kk/Page.php b/modules/Admin/Language/kk/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/kk/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/kk/Pager.php b/modules/Admin/Language/kk/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/kk/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/kk/Person.php b/modules/Admin/Language/kk/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/kk/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/kk/Platforms.php b/modules/Admin/Language/kk/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/kk/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/kk/Podcast.php b/modules/Admin/Language/kk/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/kk/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/kk/PodcastNavigation.php b/modules/Admin/Language/kk/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/kk/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/kk/Settings.php b/modules/Admin/Language/kk/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/kk/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/kk/Soundbite.php b/modules/Admin/Language/kk/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/kk/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/kk/Validation.php b/modules/Admin/Language/kk/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/kk/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/kk/VideoClip.php b/modules/Admin/Language/kk/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/kk/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/ko/AboutCastopod.php b/modules/Admin/Language/ko/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/ko/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/ko/Breadcrumb.php b/modules/Admin/Language/ko/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/ko/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/ko/Charts.php b/modules/Admin/Language/ko/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/ko/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/ko/Common.php b/modules/Admin/Language/ko/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/ko/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/ko/Countries.php b/modules/Admin/Language/ko/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/ko/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/ko/Dashboard.php b/modules/Admin/Language/ko/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/ko/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ko/Episode.php b/modules/Admin/Language/ko/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/ko/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ko/EpisodeNavigation.php b/modules/Admin/Language/ko/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/ko/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/ko/Fediverse.php b/modules/Admin/Language/ko/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/ko/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/ko/Home.php b/modules/Admin/Language/ko/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/ko/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/ko/Install.php b/modules/Admin/Language/ko/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/ko/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/ko/Navigation.php b/modules/Admin/Language/ko/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/ko/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/ko/Notifications.php b/modules/Admin/Language/ko/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/ko/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/ko/Page.php b/modules/Admin/Language/ko/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/ko/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/ko/Pager.php b/modules/Admin/Language/ko/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/ko/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/ko/Person.php b/modules/Admin/Language/ko/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/ko/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/ko/Platforms.php b/modules/Admin/Language/ko/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/ko/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/ko/Podcast.php b/modules/Admin/Language/ko/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/ko/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/ko/PodcastNavigation.php b/modules/Admin/Language/ko/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/ko/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ko/Settings.php b/modules/Admin/Language/ko/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/ko/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/ko/Soundbite.php b/modules/Admin/Language/ko/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/ko/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/ko/Validation.php b/modules/Admin/Language/ko/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/ko/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ko/VideoClip.php b/modules/Admin/Language/ko/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/ko/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/nl/AboutCastopod.php b/modules/Admin/Language/nl/AboutCastopod.php new file mode 100644 index 00000000..efefa11f --- /dev/null +++ b/modules/Admin/Language/nl/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Over Castopod', + 'host_name' => 'Servernaam', + 'version' => 'Castopod versie', + 'php_version' => 'PHP versie', + 'os' => 'Besturingssystem', + 'languages' => 'Talen', + 'update_database' => 'Database bijwerken', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up-to-date!', + ], +]; diff --git a/modules/Admin/Language/nl/Breadcrumb.php b/modules/Admin/Language/nl/Breadcrumb.php new file mode 100644 index 00000000..2d120967 --- /dev/null +++ b/modules/Admin/Language/nl/Breadcrumb.php @@ -0,0 +1,57 @@ + 'kruimelpad', + config('Admin') + ->gateway => 'Hoofdpagina', + 'podcasts' => 'podcasts', + 'episodes' => 'afleveringen', + 'subscriptions' => 'abonnementen', + 'contributors' => 'bijdragers', + 'pages' => 'paginas', + 'settings' => 'instellingen', + 'theme' => 'thema', + 'about' => 'over', + 'add' => 'toevoegen', + 'new' => 'nieuw', + 'edit' => 'bewerken', + 'persons' => 'personen', + 'publish' => 'publiceren', + 'publish-edit' => 'publicatie aanpassen', + 'publish-date-edit' => 'publicatiedatum bewerken', + 'unpublish' => 'publicatie ongedaan maken', + 'delete' => 'verwijder', + 'remove' => 'verwijder', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'geblokkeerde actoren', + 'blocked-domains' => 'geblokkeerde domeinen', + 'users' => 'gebruikers', + 'my-account' => 'mijn account', + 'change-password' => 'wachtwoord wijzigen', + 'imports' => 'imports', + 'sync-feeds' => 'feeds synchroniseren', + 'platforms' => 'platformen', + 'social' => 'sociale netwerken', + 'funding' => 'financiering', + 'monetization-other' => 'andere inkomsten', + 'analytics' => 'statistieken', + 'locations' => 'locaties', + 'webpages' => 'webpagina\'s', + 'unique-listeners' => 'unieke luisteraars', + 'players' => 'spelers', + 'listening-time' => 'afspeeltijd', + 'time-periods' => 'tijdspanne', + 'soundbites' => 'geluidsfragment', + 'video-clips' => 'videoclips', + 'embed' => 'embedbare speler', + 'notifications' => 'meldingen', + 'suspend' => 'opschorten', +]; diff --git a/modules/Admin/Language/nl/Charts.php b/modules/Admin/Language/nl/Charts.php new file mode 100644 index 00000000..213e94ab --- /dev/null +++ b/modules/Admin/Language/nl/Charts.php @@ -0,0 +1,41 @@ + 'Aflevering downloads per dienst (van de afgelopen week)', + 'by_player_weekly' => 'Aflevering downloads per afspeler (van de afgelopen week)', + 'by_player_yearly' => 'Aflevering downloads per afspeler (van de afgelopen jaar)', + 'by_device_weekly' => 'Aflevering downloads per toestel (van de afgelopen week)', + 'by_os_weekly' => 'Aflevering downloads per besturingssysteem (van de afgelopen week)', + 'podcast_by_region' => 'Aflevering downloads per regio (van de afgelopen week)', + 'unique_daily_listeners' => 'Dagelijkse unieke luisteraars', + 'unique_monthly_listeners' => 'Maandelijkse unieke luisteraars', + 'by_browser' => 'Webpagina gebruik per browser (van de afgelopen week)', + 'podcast_by_day' => 'Dagelijkse afleveringen gedownload', + 'podcast_by_month' => 'Maandelijks afleveringen gedownload', + 'episode_by_day' => 'Dagelijks afleveringen gedownload (eerste 60 dagen)', + 'episode_by_month' => 'Maandelijks afleveringen gedownload', + 'episodes_by_day' => + 'Laatste 5 afleveringen gedownload (gedurende hun eerste 60 dagen)', + 'by_country_weekly' => 'Afleveringen gedownload per land (van de afgelopen week)', + 'by_country_yearly' => 'Afleveringen gedownload per land (van de afgelopen jaar)', + 'by_domain_weekly' => 'Directe webpagina verzoeken (van de afgelopen week)', + 'by_domain_yearly' => 'Directe webpagina verzoeken (van de afgelopen jaar)', + 'by_entry_page' => 'Webpagina\'s bezoeken via landingspagina (van de afgelopen week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Dagelijkse cumulatieve afspeeltijd', + 'monthly_listening_time' => 'Maandelijkse cumulatieve afspeeltijd', + 'by_weekday' => 'Per weekdag (laatste 60 dagen)', + 'by_hour' => 'Per tijd van de dag (laatste 60 dagen)', + 'podcast_by_bandwidth' => 'Dagelijks gebruikte bandbreedte (in MB)', + 'total_storage_by_month' => 'Maandelijkse opslagruimte (in MB)', + 'total_bandwidth_by_month' => 'Maandelijkse gebruikte bandbreedte (in MB)', + 'total_bandwidth_by_month_limit' => 'Gelimiteerd tot {totalBandwidth} per maand', +]; diff --git a/modules/Admin/Language/nl/Common.php b/modules/Admin/Language/nl/Common.php new file mode 100644 index 00000000..65bbbdfe --- /dev/null +++ b/modules/Admin/Language/nl/Common.php @@ -0,0 +1,52 @@ + 'Ja', + 'no' => 'Nee', + 'cancel' => 'Annuleer', + 'optional' => 'Opties', + 'more' => 'Meer', + 'no_data' => 'Geen gegevens gevonden!', + 'close' => 'Sluiten', + 'edit' => 'Bewerken', + 'copy' => 'Kopiëer', + 'copied' => 'Gekopieerd!', + 'home' => 'Hoofdpagina', + 'explicit' => 'Expliciet', + 'powered_by' => 'Mogelijk gemaakt door {castopod}', + 'actions' => 'Acties', + 'pageInfo' => 'Pagina {currentPage} van {pageCount}', + 'go_back' => 'Terug', + 'forms' => [ + 'editor' => [ + 'write' => 'Schrijf', + 'preview' => 'Voorbeeld', + 'help' => 'Aangedreven door markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Klik om te selecteren', + 'loadingText' => 'Bezig met laden…', + 'noResultsText' => 'Geen resultaten gevonden', + 'noChoicesText' => 'Geen keuzes om van te kiezen', + 'maxItemText' => 'Kan geen extra delen toevoegen', + ], + 'upload_file' => 'Bestand uploaden', + 'remote_url' => 'Externe URL', + 'save' => 'Opslaan', + ], + 'play_episode_button' => [ + 'play' => 'Afspelen', + 'playing' => 'Wordt afgespeeld', + ], + 'size_limit' => 'Maximale grootte: {0}.', + 'choose_interact' => 'Kies hoe de interactie moet worden', + 'view' => 'Weergeven', +]; diff --git a/modules/Admin/Language/nl/Countries.php b/modules/Admin/Language/nl/Countries.php new file mode 100644 index 00000000..82cb1990 --- /dev/null +++ b/modules/Admin/Language/nl/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Verenigde Arabische Emiraten', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua en Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albanië', + 'AM' => 'Armenië', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentinië', + 'AS' => 'Amerikaans-Samoa', + 'AT' => 'Oostenrijk', + 'AU' => 'Australië', + 'AW' => 'Aruba', + 'AX' => 'Åland', + 'AZ' => 'Azerbeidzjan', + 'BA' => 'Bosnië en Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'België', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgarije', + 'BH' => 'Bahrein', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint-Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei', + 'BO' => 'Bolivië', + 'BQ' => 'Caribisch Nederland', + 'BR' => 'Brazilië', + 'BS' => 'Bahama\'s', + 'BT' => 'Bhutan', + 'BV' => 'Bouveteiland', + 'BW' => 'Botswana', + 'BY' => 'Wit-Rusland', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocoseilanden', + 'CD' => 'Congo-Kinshasa', + 'CF' => 'Centraal Afrikaanse Republiek', + 'CG' => 'Congo-Brazzaville', + 'CH' => 'Zwitserland', + 'CI' => "Ivoorkust", + 'CK' => 'Cookeilanden', + 'CL' => 'Chili', + 'CM' => 'Kameroen', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Kaapverdië', + 'CW' => 'Curaçao', + 'CX' => 'Christmaseiland', + 'CY' => 'Cyprus', + 'CZ' => 'Tsjechië', + 'DE' => 'Duitsland', + 'DJ' => 'Djibouti', + 'DK' => 'Denemarken', + 'DM' => 'Dominica', + 'DO' => 'Dominicaanse Republiek', + 'DZ' => 'Algerije', + 'EC' => 'Ecuador', + 'EE' => 'Estland', + 'EG' => 'Egypte', + 'EH' => 'Westelijke Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spanje', + 'ET' => 'Ethiopië', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falklandeilanden', + 'FM' => 'Micronesië', + 'FO' => 'Faeröer', + 'FR' => 'Frankrijk', + 'GA' => 'Gabon', + 'GB' => 'Verenigd Koninkrijk', + 'GD' => 'Grenada', + 'GE' => 'Georgië', + 'GF' => 'Frans-Guyana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Groenland', + 'GM' => 'Gambia', + 'GN' => 'Guinee', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatoriaal-Guinea', + 'GR' => 'Griekenland', + 'GS' => 'Zuid-Georgia en de Zuidelijke Sandwicheilanden', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinee-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard- en MacDonaldeilanden', + 'HN' => 'Honduras', + 'HR' => 'Kroatië', + 'HT' => 'Haïti', + 'HU' => 'Hongarije', + 'ID' => 'Indonesië', + 'IE' => 'Ierland', + 'IL' => 'Israël', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'Britse Gebieden in de Indische Oceaan', + 'IQ' => 'Irak', + 'IR' => 'Iran, Islamitische Republiek', + 'IS' => 'Ijsland', + 'IT' => 'Italië', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordanië', + 'JP' => 'Japan', + 'KE' => 'Kenia', + 'KG' => 'Kirgizië', + 'KH' => 'Cambodja', + 'KI' => 'Kiribati', + 'KM' => 'Comoren', + 'KN' => 'Saint Kitts en Nevis', + 'KP' => "Korea, Democratische Volksrepubliek", + 'KR' => 'Zuid-Korea', + 'KW' => 'Koeweit', + 'KY' => 'Kaaimaneilanden', + 'KZ' => 'Kazachstan', + 'LA' => "Lao Democratische Volksrepubliek", + 'LB' => 'Lebanon', + 'LC' => 'Sint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Litauen', + 'LU' => 'Luxemburg', + 'LV' => 'Letland', + 'LY' => 'Libië', + 'MA' => 'Marokko', + 'MC' => 'Monaco', + 'MD' => 'Moldavië, Republiek', + 'ME' => 'Montenegro', + 'MF' => 'Sint Maarten (Frans deel)', + 'MG' => 'Madagaskar', + 'MH' => 'Marshalleilanden', + 'MK' => 'Macedonië', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolië', + 'MO' => 'Macau', + 'MP' => 'Noordelijke Mariana eilanden', + 'MQ' => 'Martinique', + 'MR' => 'Mauritanië', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldiven', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Maleisië', + 'MZ' => 'Mozambique', + 'N/A' => 'Niet van toepassing (lokale IP…)', + 'NA' => 'Namibië', + 'NC' => 'Nieuw-Caledonië', + 'NE' => 'Niger', + 'NF' => 'Norfolk Eiland', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Nederland', + 'NO' => 'Noorwegen', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nieuw-Zeeland', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Frans-Polynesië', + 'PG' => 'Papua Nieuw-Guinea', + 'PH' => 'Filipijnen', + 'PK' => 'Pakistan', + 'PL' => 'Polen', + 'PM' => 'Saint-Pierre en Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Roemenië', + 'RS' => 'Servië', + 'RU' => 'Russische Federatie', + 'RW' => 'Rwanda', + 'SA' => 'Saudi-Arabië', + 'SB' => 'Solomon-eilanden', + 'SC' => 'Seychellen', + 'SD' => 'Soedan', + 'SE' => 'Zweden', + 'SG' => 'Singapore', + 'SH' => 'Sint-Helena, Ascension en Tristan da Cunha', + 'SI' => 'Slovenië', + 'SJ' => 'Spitsbergen en Jan Mayen', + 'SK' => 'Slowakije', + 'SL' => 'Siërra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalië', + 'SR' => 'Suriname', + 'SS' => 'Zuid-Soedan', + 'ST' => 'Sao Tomé en Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Nederlands deel)', + 'SY' => 'Syrië, Arabische Republiek', + 'SZ' => 'Swaziland', + 'TC' => 'Turks- en Caicos-eilanden', + 'TD' => 'Tsjaad', + 'TF' => 'Franse Gebieden in de zuidelijke Indische Oceaan', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tadzjikistan', + 'TK' => 'Tokelau', + 'TL' => 'Oost-Timor', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunesië', + 'TO' => 'Tonga', + 'TR' => 'Turkije', + 'TT' => 'Trinidad en Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania', + 'UA' => 'Oekraïne', + 'UG' => 'Oeganda', + 'UM' => 'Kleine afgelegen eilanden van de Verenigde Staten', + 'US' => 'Verenigde Staten', + 'UY' => 'Uruguay', + 'UZ' => 'Oezbekistan', + 'VA' => 'Holy See (Vaticaanstad)', + 'VC' => 'Sint Vincent en de Grenadines', + 'VE' => 'Venezuela, Bolivariaanse Republiek', + 'VG' => 'Britse Maagdeneilanden', + 'VI' => 'Maagdeneilanden, Amerikaanse', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis en Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Mayotte', + 'ZA' => 'Zuid-Afrika', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/nl/Dashboard.php b/modules/Admin/Language/nl/Dashboard.php new file mode 100644 index 00000000..15c43acb --- /dev/null +++ b/modules/Admin/Language/nl/Dashboard.php @@ -0,0 +1,28 @@ + 'Beheerdersdashboard', + 'welcome_message' => 'Welkom bij de beheeromgeving!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Geen gepubliceerde podcast', + 'last_published' => 'Laatst gepubliceerd op {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Afleveringen', + 'not_found' => 'Geen gepubliceerde aflevering', + 'last_published' => 'Laatst gepubliceerd op {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Opslagruimte', + 'subtitle' => '{totalUploaded} van {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/nl/Episode.php b/modules/Admin/Language/nl/Episode.php new file mode 100644 index 00000000..70a11518 --- /dev/null +++ b/modules/Admin/Language/nl/Episode.php @@ -0,0 +1,225 @@ + 'Seizoen {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Aflevering {episodeNumber}', + 'number_abbr' => 'Af. {episodeNumber}', + 'season_episode' => 'Seizoen {seasonNumber} aflevering {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# reactie} + other {# reacties} + }', + 'all_podcast_episodes' => 'Alle podcast afleveringen', + 'back_to_podcast' => 'Terug naar podcast', + 'edit' => 'Bewerken', + 'preview' => 'Voorbeeld', + 'publish' => 'Publiceren', + 'publish_edit' => 'Publicatie bewerken', + 'publish_date_edit' => 'Publicatiedatum bewerken', + 'unpublish' => 'Publicatie ongedaan maken', + 'publish_error' => 'Aflevering is reeds gepubliceerd.', + 'publish_edit_error' => 'Aflevering is reeds gepubliceerd.', + 'publish_cancel_error' => 'Aflevering is reeds gepubliceerd.', + 'publish_date_edit_error' => 'Aflevering is nog niet gepubliceerd, u kunt de publicatiedatum niet bewerken.', + 'publish_date_edit_future_error' => 'Aflevering publicatiedatum kan alleen worden ingesteld op een datum in het verleden! Als u het opnieuw wilt inplannen, verwijder dan de publicatie eerst.', + 'publish_date_edit_success' => 'De publicatiedatum van aflevering is met succes bijgewerkt!', + 'unpublish_error' => 'Aflevering is niet gepubliceerd.', + 'delete' => 'Verwijder', + 'go_to_page' => 'Ga naar pagina', + 'create' => 'Aflevering toevoegen', + 'publication_status' => [ + 'published' => 'Gepubliceerd', + 'with_podcast' => 'Gepubliceerd', + 'scheduled' => 'Gepland', + 'not_published' => 'Niet gepubliceerd', + ], + 'with_podcast_hint' => 'Nog te publiceren op hetzelfde moment als de podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Zoek naar een aflevering', + 'clear' => 'Wis zoekopdracht', + 'submit' => 'Zoeken', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# aflevering} + other {# afleveringen} + }', + 'episode' => 'Aflevering', + 'visibility' => 'Zichtbaarheid', + 'downloads' => 'Downloads', + 'comments' => 'Reacties', + 'actions' => 'Acties', + ], + 'messages' => [ + 'createSuccess' => 'Aflevering is succesvol aangemaakt!', + 'editSuccess' => 'Aflevering is succesvol bijgewerkt!', + 'publishSuccess' => '{publication_status, select, + published {Deze aflevering is nog niet gepubliceerd!} + scheduled {Deze aflevering is successvol gepland!} + with_podcast {Deze aflevering zal op hetzelfde moment als de podcast worden gepubliceerd.} + other {Deze aflevering is nog niet gepubliceerd.} + }', + 'publishCancelSuccess' => 'Aflevering publicatie is geannuleerd!', + 'unpublishBeforeDeleteTip' => 'Je moet de publicatie van de aflevering ongedaan maken voordat je deze verwijdert.', + 'scheduleDateError' => 'Geplande datum moet worden ingesteld!', + 'deletePublishedEpisodeError' => 'Je moet de publicatie van de aflevering ongedaan maken voordat je deze verwijdert.', + 'deleteSuccess' => 'Aflevering succesvol verwijderd!', + 'deleteError' => 'Kan de aflevering niet verwijderen {type, select, + transcript {transcript} + chapters {hoofdstukken} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Mislukt om te verwijderen {type, select, + transcript {transcript} + chapters {hoofdstukken} + image {cover} + audio {audio} + other {media} + } bestand {file_key}. Je kunt het handmatig verwijderen van je schijf.', + 'sameSlugError' => 'Er bestaat al een aflevering met de gekozen slug.', + ], + 'form' => [ + 'file_size_error' => + 'Uw bestand is te groot! Maximale grootte is {0}. Verhoog de `memory_limit`, `upload_max_filesize` en `post_max_size` waarden in je php configuratiebestand en herstart vervolgens je webserver om je bestand te uploaden.', + 'audio_file' => 'Geluidsbestand', + 'audio_file_hint' => 'Kies een .mp3 of .m4a audiobestand.', + 'info_section_title' => 'Aflevering informatie', + 'cover' => 'Aflevering omslag', + 'cover_hint' => + 'Als je geen omslag instelt, zal de podcast omslag worden gebruikt.', + 'cover_size_hint' => 'Omslag moet minstens 1400px breed en hoog zijn.', + 'title' => 'Titel', + 'title_hint' => + 'Moet een duidelijke en beknopte afleveringsnaam bevatten. Geef hier geen aflevering of seizoen nummers op.', + 'permalink' => 'Permanente koppeling', + 'season_number' => 'Seizoen', + 'episode_number' => 'Aflevering', + 'type' => [ + 'label' => 'Soort', + 'full' => 'Vol', + 'full_hint' => 'Volledige inhoud (aflevering)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Korte, promotionele inhoud die een voorbeeld van de huidige show vertegenwoordigt', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra inhoud voor de show (bijvoorbeeld achter de scène-info of interviews met de deelnemers) of cross-promotionele inhoud voor een andere show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Aflevering mag alleen toegankelijk zijn voor premium abonnees', + 'parental_advisory' => [ + 'label' => 'Ouderlijk advies', + 'hint' => 'Bevat de aflevering de expliciete inhoud?', + 'undefined' => 'niet gedefineerd', + 'clean' => 'Fatsoenlijk', + 'explicit' => 'Expliciet', + ], + 'show_notes_section_title' => 'Toon notities', + 'show_notes_section_subtitle' => + 'Maximaal 4000 tekens, wees duidelijk en beknopt. Notities helpen potentiële luisteraars om de aflevering te vinden.', + 'description' => 'Omschrijving', + 'description_footer' => 'Omschrijving voettekst', + 'description_footer_hint' => + 'Deze tekst wordt aan het einde van elke aflevering beschrijving toegevoegd, het is een goede plek om bijvoorbeeld je sociale links te plaatsen.', + 'additional_files_section_title' => 'Extra bestanden', + 'additional_files_section_subtitle' => + 'Deze bestanden kunnen door andere platforms worden gebruikt om uw publiek een betere ervaring te bieden. Zie de {podcastNamespaceLink} voor meer informatie.', + 'location_section_title' => 'Locatie', + 'location_section_subtitle' => 'Over welke plaats gaat deze aflevering?', + 'location_name' => 'Locatienaam of adres', + 'location_name_hint' => 'Dit kan een echte of fictieve locatie zijn', + 'transcript' => 'Transcript (ondertiteling / gesloten ondertitels)', + 'transcript_hint' => 'Alleen .srt of .vtt zijn toegestaan.', + 'transcript_download' => 'Transcriptie downloaden', + 'transcript_file' => 'Transcript-bestand (.srt of .vtt)', + 'transcript_remote_url' => 'Externe URL voor transcript', + 'transcript_file_delete' => 'Verwijder transcript-bestand', + 'chapters' => 'Hoofdstukken', + 'chapters_hint' => 'Bestand moet in JSON Hoofdstuk indeling zijn.', + 'chapters_download' => 'Hoofdstukken downloaden', + 'chapters_file' => 'Hoofdstukken bestand', + 'chapters_remote_url' => 'Externe URL voor hoofdstukken bestand', + 'chapters_file_delete' => 'Verwijder hoofdstukken bestand', + 'advanced_section_title' => 'Geavanceerde parameters', + 'advanced_section_subtitle' => + 'Als je RSS tags nodig hebt die Castopod niet afhandelt, stel ze hier in.', + 'custom_rss' => 'Aangepaste RSS labels voor de aflevering', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Aflevering aanmaken', + 'submit_edit' => 'Aflevering opslaan', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Schrijf uw bericht…', + 'publication_date' => 'Publicatiedatum', + 'publication_method' => [ + 'now' => 'Nu', + 'schedule' => 'Plannen', + 'with_podcast' => 'Publiceer samen met podcast', + ], + 'scheduled_publication_date' => 'Gepland publicatiedatum', + 'scheduled_publication_date_clear' => 'Publicatiedatum wissen', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publiceren', + 'submit_edit' => 'Publicatie bewerken', + 'cancel_publication' => 'Publicatie annuleren', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Toch publiceren', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nieuwe publicatiedatum', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Publicatiedatum bewerken', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Publicatie ongedaan maken', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Verwijderen', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Kopieer adres naar klembord', + 'dark' => 'Donker', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Licht', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Voorbeeld', + ], +]; diff --git a/modules/Admin/Language/nl/EpisodeNavigation.php b/modules/Admin/Language/nl/EpisodeNavigation.php new file mode 100644 index 00000000..34577f82 --- /dev/null +++ b/modules/Admin/Language/nl/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Hoofdpagina', + 'episode-edit' => 'Aflevering bewerken', + 'episode-persons-manage' => 'Personen beheren', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Videoclips', + 'video-clips-create' => 'Nieuwe videoclip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/nl/Fediverse.php b/modules/Admin/Language/nl/Fediverse.php new file mode 100644 index 00000000..2ce69a02 --- /dev/null +++ b/modules/Admin/Language/nl/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Het account werd niet gevonden!', + 'blockActorSuccess' => '{actor} is geblokkeerd!', + 'unblockActorSuccess' => 'Acteur is gedeblokkeerd!', + 'blockDomainSuccess' => '{domain} is geblokkeerd!', + 'unblockDomainSuccess' => '{domain} is gedeblokkeerd!', + ], + 'blocked_actors' => 'Geblokkeerde accounts', + 'blocked_domains' => 'Geblokkeerde domeinen', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domeinnaam', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domeinnaam', + 'unblock' => 'Deblokkeren', + ], +]; diff --git a/modules/Admin/Language/nl/Home.php b/modules/Admin/Language/nl/Home.php new file mode 100644 index 00000000..8620f125 --- /dev/null +++ b/modules/Admin/Language/nl/Home.php @@ -0,0 +1,14 @@ + 'Alle podcasts', + 'no_podcast' => 'Geen podcast gevonden', +]; diff --git a/modules/Admin/Language/nl/Install.php b/modules/Admin/Language/nl/Install.php new file mode 100644 index 00000000..cfd92f3f --- /dev/null +++ b/modules/Admin/Language/nl/Install.php @@ -0,0 +1,61 @@ + 'Handmatige configuratie', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostnaam', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Databasenaam', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'Bestand', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Volgende', + 'submit' => 'Installatie voltooien', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'E-mail', + 'username' => 'Gebruikersnaam', + 'password' => 'Wachtwoord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/nl/Navigation.php b/modules/Admin/Language/nl/Navigation.php new file mode 100644 index 00000000..62f09b7c --- /dev/null +++ b/modules/Admin/Language/nl/Navigation.php @@ -0,0 +1,44 @@ + 'Zijbalk tonen/verbergen', + 'go_to_website' => 'Ga naar website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Niet geautoriseerd', + 'dashboard' => 'Dashboard', + 'admin' => 'Hoofdpagina', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Alle podcasts', + 'podcast-create' => 'Nieuwe podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Importeer een podcast', + 'persons' => 'Personen', + 'person-list' => 'Alle personen', + 'person-create' => 'Nieuwe persoon', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Geblokkeerde accounts', + 'fediverse-blocked-domains' => 'Geblokkeerde domeinen', + 'users' => 'Gebruikers', + 'user-list' => 'Alle gebruikers', + 'user-create' => 'Nieuwe gebruiker', + 'pages' => 'Pagina\'s', + 'page-list' => 'Alle pagina\'s', + 'page-create' => 'Nieuwe pagina', + 'settings' => 'Instellingen', + 'settings-general' => 'Algemeen', + 'settings-theme' => 'Thema', + 'admin-about' => 'Over', + 'account' => [ + 'my-account' => 'Mijn account', + 'change-password' => 'Wachtwoord wijzigen', + 'logout' => 'Uitloggen', + ], +]; diff --git a/modules/Admin/Language/nl/Notifications.php b/modules/Admin/Language/nl/Notifications.php new file mode 100644 index 00000000..76d9697b --- /dev/null +++ b/modules/Admin/Language/nl/Notifications.php @@ -0,0 +1,19 @@ + 'Meldingen', + 'reply' => '{actor_username} heeft op uw bericht gereageerd', + 'favourite' => '{actor_username} heeft je post als favoriet gemarkeerd', + 'reblog' => '{actor_username} heeft je bericht gedeeld', + 'follow' => '{actor_username} volgt je nu', + 'no_notifications' => 'Geen meldingen', + 'mark_all_as_read' => 'Alles als gelezen markeren', +]; diff --git a/modules/Admin/Language/nl/Page.php b/modules/Admin/Language/nl/Page.php new file mode 100644 index 00000000..566bbd92 --- /dev/null +++ b/modules/Admin/Language/nl/Page.php @@ -0,0 +1,30 @@ + 'Terug naar de hoofdpagina', + 'page' => 'Pagina', + 'all_pages' => 'Alle pagina\'s', + 'create' => 'Nieuwe pagina', + 'go_to_page' => 'Ga naar pagina', + 'edit' => 'Pagina bewerken', + 'delete' => 'Pagina verwijderen', + 'form' => [ + 'title' => 'Titel', + 'permalink' => 'Permalink', + 'content' => 'Inhoud', + 'submit_create' => 'Pagina aanmaken', + 'submit_edit' => 'Opslaan', + ], + 'messages' => [ + 'createSuccess' => 'De pagina "{pageTitle}" is succesvol aangemaakt!', + 'editSuccess' => 'De pagina is succesvol bijgewerkt!', + ], +]; diff --git a/modules/Admin/Language/nl/Pager.php b/modules/Admin/Language/nl/Pager.php new file mode 100644 index 00000000..210448d8 --- /dev/null +++ b/modules/Admin/Language/nl/Pager.php @@ -0,0 +1,21 @@ + 'Paginanavigatie', + 'first' => 'Eerste', + 'previous' => 'Vorige', + 'next' => 'Volgende', + 'last' => 'Laatste', + 'older' => 'Ouder', + 'newer' => 'Nieuwer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/nl/Person.php b/modules/Admin/Language/nl/Person.php new file mode 100644 index 00000000..19a25696 --- /dev/null +++ b/modules/Admin/Language/nl/Person.php @@ -0,0 +1,65 @@ + 'Personen', + 'all_persons' => 'Alle personen', + 'no_person' => 'Niemand gevonden!', + 'create' => 'Een persoon aanmaken', + 'view' => 'Persoon weergeven', + 'edit' => 'Persoon bewerken', + 'delete' => 'Persoon verwijderen', + 'messages' => [ + 'createSuccess' => 'Persoon is succesvol aangemaakt!', + 'editSuccess' => 'Persoon is succesvol bijgewerkt!', + 'deleteSuccess' => 'Persoon is verwijderd!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Volledige naam', + 'full_name_hint' => 'Dit is de volledige naam of alias van de persoon.', + 'unique_name' => 'Unieke naam', + 'unique_name_hint' => 'Gebruikt voor URLs', + 'information_url' => 'Informatie URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Persoon aanmaken', + 'submit_edit' => 'Persoon opslaan', + ], + 'podcast_form' => [ + 'title' => 'Personen beheren', + 'add_section_title' => 'Voeg personen toe aan deze podcast', + 'add_section_subtitle' => 'U kunt meerdere personen en rollen kiezen.', + 'persons' => 'Personen', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Rollen', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Verwijderen', + ], + 'episode_form' => [ + 'title' => 'Personen beheren', + 'add_section_title' => 'Voeg personen toe aan deze aflevering', + 'add_section_subtitle' => 'U kunt meerdere personen en rollen kiezen.', + 'persons' => 'Personen', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Rollen', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Verwijderen', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/nl/Platforms.php b/modules/Admin/Language/nl/Platforms.php new file mode 100644 index 00000000..67f69651 --- /dev/null +++ b/modules/Admin/Language/nl/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Sociale netwerken', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Ga naar de {platformName} website', + 'register' => 'Registreren', + 'submit_url' => 'Dien jouw podcast in op {platformName}', + 'your_link' => 'Jouw link', + 'your_id' => [ + 'podcasting' => 'Jouw ID', + 'social' => 'Jouw ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => '{platformName} verwijderen', + 'submit' => 'Opslaan', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/nl/Podcast.php b/modules/Admin/Language/nl/Podcast.php new file mode 100644 index 00000000..12cf5f2a --- /dev/null +++ b/modules/Admin/Language/nl/Podcast.php @@ -0,0 +1,330 @@ + 'Alle podcasts', + 'no_podcast' => 'Geen podcast gevonden!', + 'create' => 'Podcast aanmaken', + 'import' => 'Podcast importeren', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Nieuwe aflevering', + 'view' => 'Podcast bekijken', + 'edit' => 'Podcast bewerken', + 'publish' => 'Podcast publiceren', + 'publish_edit' => 'Publicatie bewerken', + 'delete' => 'Podcast verwijderen', + 'see_episodes' => 'Afleveringen bekijken', + 'see_contributors' => 'Bekijk bijdragers', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Ga naar pagina', + 'latest_episodes' => 'Laatste afleveringen', + 'see_all_episodes' => 'Toon alle afleveringen', + 'draft' => 'Concept', + 'messages' => [ + 'createSuccess' => 'Podcast succesvol aangemaakt!', + 'editSuccess' => 'Podcast is succesvol bijgewerkt!', + 'importSuccess' => 'Podcast is succesvol geïmporteerd!', + 'deleteSuccess' => 'Podcast @{podcast_handle} succesvol verwijderd!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is al up-to-date.', + 'publishError' => 'Deze podcast is al gepubliceerd of gepland voor publicatie.', + 'publishEditError' => 'Deze podcast is niet gepland voor publicatie.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Titel', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Soort', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Omschrijving', + 'classification_section_title' => 'Classificatie', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Taal', + 'category' => 'Categorie', + 'category_placeholder' => 'Selecteer een categorie…', + 'other_categories' => 'Andere categorieën', + 'parental_advisory' => [ + 'label' => 'Ouderlijk advies', + 'hint' => 'Bevat de aflevering de expliciete inhoud?', + 'undefined' => 'niet gedefineerd', + 'clean' => 'Clean', + 'explicit' => 'Expliciet', + ], + 'author_section_title' => 'Auteur', + 'author_section_subtitle' => 'Wie beheert de podcast?', + 'owner_name' => 'Naam eigenaar', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Uitgever', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Auteursrecht', + 'location_section_title' => 'Locatie', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Verdien geld dankzij uw publiek.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Samenwerking', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Podcast aanmaken', + 'submit_edit' => 'Podcast opslaan', + ], + 'category_options' => [ + 'uncategorized' => 'niet gecategoriseerd', + 'arts' => 'Kunsten', + 'business' => 'Zakelijk', + 'comedy' => 'Komedie', + 'education' => 'Educatie', + 'fiction' => 'Fictie', + 'government' => 'Government', + 'health_and_fitness' => 'Gezondheid & Fitness', + 'history' => 'Geschiedenis', + 'kids_and_family' => 'Kinderen & Familie', + 'leisure' => 'Vrije tijd', + 'music' => 'Muziek', + 'news' => 'Nieuws', + 'religion_and_spirituality' => 'Geloof & Spiritualiteit', + 'science' => 'Wetenschap', + 'society_and_culture' => 'Maatschappij & Cultuur', + 'sports' => 'Sporten', + 'technology' => 'Technologie', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Boeken', + 'design' => 'Ontwerp', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Voeding', + 'performing_arts' => 'Podiumkunsten', + 'visual_arts' => 'Beeldende kunsten', + 'careers' => 'Carrières', + 'entrepreneurship' => 'Ondernemerschap', + 'investing' => 'Investeren', + 'management' => 'Beheer', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sportnieuws', + 'tech_news' => 'Tech News', + 'buddhism' => 'Boeddhisme', + 'christianity' => 'Christendom', + 'hinduism' => 'Hindoeïsme', + 'islam' => 'Islam', + 'judaism' => 'Jodendom', + 'religion' => 'Religie', + 'spirituality' => 'Spiritualiteit', + 'astronomy' => 'Astronomie', + 'chemistry' => 'Chemie', + 'earth_sciences' => 'Aardwetenschappen', + 'life_sciences' => 'Levenswetenschappen', + 'mathematics' => 'Wiskunde', + 'natural_sciences' => 'Natuurwetenschappen', + 'nature' => 'Natuur', + 'physics' => 'Fysica', + 'social_sciences' => 'Sociale wetenschappen', + 'documentary' => 'Documentary', + 'personal_journals' => 'Persoonlijke dagboeken', + 'philosophy' => 'Filosofie', + 'places_and_travel' => 'Plaatsen & Reizen', + 'relationships' => 'Relaties', + 'baseball' => 'Honkbal', + 'basketball' => 'Basketbal', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Voetbal', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Rennen', + 'soccer' => 'Voetbal', + 'swimming' => 'Zwemmen', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleybal', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Worstelen', + 'after_shows' => 'After Shows', + 'film_history' => 'Filmgeschiedenis', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV-beoordelingen', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Schrijf uw bericht…', + 'submit' => 'Publiceren', + 'publication_date' => 'Publicatiedatum', + 'publication_method' => [ + 'now' => 'Nu', + 'schedule' => 'Plannen', + ], + 'scheduled_publication_date' => 'Gepland publicatiedatum', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Publicatie bewerken', + 'cancel_publication' => 'Publicatie annuleren', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Toch publiceren', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'De podcast is nog niet gepubliceerd.', + 'scheduled' => 'Deze podcast is gepland voor publicatie op {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Verwijderen', + ], + 'by' => 'Door {publisher}', + 'season' => 'Seizoen {seasonNumber}', + 'list_of_episodes_year' => '{year} afleveringen ({episodeCount})', + 'list_of_episodes_season' => + 'Seizoen {seasonNumber} afleveringen ({episodeCount})', + 'no_episode' => 'Er zijn geen afleveringen gevonden!', + 'follow' => 'Volgen', + 'followers' => '{numberOfFollowers, plural, + one {# volger} + other {# volgers} + }', + 'posts' => '{numberOfPosts, plural, + one {# bericht} + other {# berichten} + }', + 'activity' => 'Activiteit', + 'episodes' => 'Afleveringen', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Vind {podcastTitle} op', + 'listen_on' => 'Beluister op', +]; diff --git a/modules/Admin/Language/nl/PodcastNavigation.php b/modules/Admin/Language/nl/PodcastNavigation.php new file mode 100644 index 00000000..6cbfcdbb --- /dev/null +++ b/modules/Admin/Language/nl/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Hoofdpagina', + 'podcast-edit' => 'Podcast bewerken', + 'podcast-persons-manage' => 'Personen beheren', + 'podcast-imports' => 'Podcast importeren', + 'podcast-imports-sync' => 'Synchroniseer feeds', + 'episodes' => 'Afleveringen', + 'episode-list' => 'Alle afleveringen', + 'episode-create' => 'Nieuwe aflevering', + 'analytics' => 'Statistieken', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locaties', + 'podcast-analytics-unique-listeners' => 'Unieke luisteraars', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Luistertijd', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'Alle abonnementen', + 'subscription-create' => 'Abonnement toevoegen', + 'contributors' => 'Bijdragers', + 'contributor-list' => 'Alle bijdragers', + 'contributor-add' => 'Bijdragers toevoegen', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Sociale netwerken', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Andere', +]; diff --git a/modules/Admin/Language/nl/Settings.php b/modules/Admin/Language/nl/Settings.php new file mode 100644 index 00000000..5ce212db --- /dev/null +++ b/modules/Admin/Language/nl/Settings.php @@ -0,0 +1,58 @@ + 'Algemene instellingen', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Opslaan', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Afbeeldingen', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Afbeeldingen regenereren', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Huishouden', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Thema', + 'accent_section_title' => 'Accentkleur', + 'accent_section_subtitle' => 'Kies de kleur om het uiterlijk van alle openbare pagina\'s te bepalen.', + 'pine' => 'Den', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Meer', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Opslaan', + 'setInstanceThemeSuccess' => 'Thema is succesvol bijgewerkt!', + ], +]; diff --git a/modules/Admin/Language/nl/Soundbite.php b/modules/Admin/Language/nl/Soundbite.php new file mode 100644 index 00000000..0f67581e --- /dev/null +++ b/modules/Admin/Language/nl/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Begintijd', + 'duration' => 'Duur', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/nl/Validation.php b/modules/Admin/Language/nl/Validation.php new file mode 100644 index 00000000..1e61ef35 --- /dev/null +++ b/modules/Admin/Language/nl/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is geen afbeelding of niet van de juiste verhouding.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/nl/VideoClip.php b/modules/Admin/Language/nl/VideoClip.php new file mode 100644 index 00000000..c277d850 --- /dev/null +++ b/modules/Admin/Language/nl/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Videoclips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'in wachtrij', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'in behandeling', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'actief', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'mislukt', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Liggend', + 'portrait' => 'Portrait', + 'squared' => 'Vierkant', + ], + 'form' => [ + 'title' => 'Nieuwe videoclip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Kies een formaat', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Selecteer een thema', + 'start_time' => 'Begintijd', + 'duration' => 'Duur', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/nn-no/AboutCastopod.php b/modules/Admin/Language/nn-no/AboutCastopod.php new file mode 100644 index 00000000..cdcce825 --- /dev/null +++ b/modules/Admin/Language/nn-no/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Om Castopod', + 'host_name' => 'Vertsnamn', + 'version' => 'Castopod-versjon', + 'php_version' => 'PHP-versjon', + 'os' => 'Operativsystem', + 'languages' => 'Språk', + 'update_database' => 'Oppdater databasen', + 'messages' => [ + 'databaseUpdateSuccess' => 'Databasen er oppdatert!', + ], +]; diff --git a/modules/Admin/Language/nn-no/Breadcrumb.php b/modules/Admin/Language/nn-no/Breadcrumb.php new file mode 100644 index 00000000..422e71df --- /dev/null +++ b/modules/Admin/Language/nn-no/Breadcrumb.php @@ -0,0 +1,57 @@ + 'navigeringslenke', + config('Admin') + ->gateway => 'Heim', + 'podcasts' => 'podkastar', + 'episodes' => 'episodar', + 'subscriptions' => 'tingingar', + 'contributors' => 'bidragsytarar', + 'pages' => 'sider', + 'settings' => 'innstillingar', + 'theme' => 'bunad', + 'about' => 'om', + 'add' => 'legg til', + 'new' => 'ny', + 'edit' => 'rediger', + 'persons' => 'personar', + 'publish' => 'legg ut', + 'publish-edit' => 'rediger publiseringa', + 'publish-date-edit' => 'rediger publiseringsdato', + 'unpublish' => 'avpubliser', + 'delete' => 'slett', + 'remove' => 'fjern', + 'fediverse' => 'fødiverset', + 'blocked-actors' => 'blokkerte aktørar', + 'blocked-domains' => 'blokkerte domene', + 'users' => 'brukarar', + 'my-account' => 'kontoen min', + 'change-password' => 'endre passord', + 'imports' => 'importar', + 'sync-feeds' => 'synkroniser straumar', + 'platforms' => 'plattformer', + 'social' => 'sosiale nettverk', + 'funding' => 'finansiering', + 'monetization-other' => 'andre måtar å tena pengar på', + 'analytics' => 'analysar', + 'locations' => 'stader', + 'webpages' => 'nettsider', + 'unique-listeners' => 'unike lyttarar', + 'players' => 'spelarar', + 'listening-time' => 'lyttetid', + 'time-periods' => 'tidsperiodar', + 'soundbites' => 'lydbetar', + 'video-clips' => 'videoklypp', + 'embed' => 'innbyggbar spelar', + 'notifications' => 'varslingar', + 'suspend' => 'utvis', +]; diff --git a/modules/Admin/Language/nn-no/Charts.php b/modules/Admin/Language/nn-no/Charts.php new file mode 100644 index 00000000..5890aa0d --- /dev/null +++ b/modules/Admin/Language/nn-no/Charts.php @@ -0,0 +1,41 @@ + 'Episodenedlastingar etter tenest (siste veka)', + 'by_player_weekly' => 'Episodenedlastingar etter spelar (siste veka)', + 'by_player_yearly' => 'Episodenedlastingar etter spelar (siste året)', + 'by_device_weekly' => 'Episodenedlastingar etter eining (siste veka)', + 'by_os_weekly' => 'Episodenedlastingar etter operativsystem (siste veka)', + 'podcast_by_region' => 'Episodenedlastingar etter område (siste veka)', + 'unique_daily_listeners' => 'Unike lyttarar pr. dag', + 'unique_monthly_listeners' => 'Unike lyttarar pr. månad', + 'by_browser' => 'Nettsidebruk etter nettlesar (siste veka)', + 'podcast_by_day' => 'Daglege episodenedlastingar', + 'podcast_by_month' => 'Episodenedlastingar pr. månad', + 'episode_by_day' => 'Daglege episodenedlastingar (dei fyrste 60 dagane)', + 'episode_by_month' => 'Episodenedlastingar pr. månad', + 'episodes_by_day' => + 'Nedlastingar av dei siste 5 episodane (i løpet av dei fyrste 60 dagane)', + 'by_country_weekly' => 'Episodenedlastingar etter land (siste veka)', + 'by_country_yearly' => 'Episodenedlastingar etter land (siste året)', + 'by_domain_weekly' => 'Nettsidevisingar etter kjelde (siste veka)', + 'by_domain_yearly' => 'Nettsidevisingar etter kjelde (siste året)', + 'by_entry_page' => 'Nettsidevisingar etter landingsside (siste veka)', + 'podcast_bots' => 'Botar (søkjeprogram)', + 'daily_listening_time' => 'Dagleg kumulativ lyttetid', + 'monthly_listening_time' => 'Månadleg kumulativ lyttetid', + 'by_weekday' => 'Etter vekedag (dei siste 60 dagane)', + 'by_hour' => 'Etter tid på dagen (dei siste 60 dagane)', + 'podcast_by_bandwidth' => 'Dagleg bandbreidde (i MB)', + 'total_storage_by_month' => 'Lagrinsgsplass kvar månad (i MB)', + 'total_bandwidth_by_month' => 'Brukt bandbreidd pr. månad (i MB)', + 'total_bandwidth_by_month_limit' => 'Avgrensa til {totalBandwidth} pr. månad', +]; diff --git a/modules/Admin/Language/nn-no/Common.php b/modules/Admin/Language/nn-no/Common.php new file mode 100644 index 00000000..f9678459 --- /dev/null +++ b/modules/Admin/Language/nn-no/Common.php @@ -0,0 +1,52 @@ + 'Ja', + 'no' => 'Nei', + 'cancel' => 'Avbryt', + 'optional' => 'Valfritt', + 'more' => 'Meir', + 'no_data' => 'Fann ingen data!', + 'close' => 'Lukk', + 'edit' => 'Rediger', + 'copy' => 'Kopier', + 'copied' => 'Kopiert!', + 'home' => 'Heim', + 'explicit' => 'Grov prat', + 'powered_by' => 'Køyrer på {castopod}', + 'actions' => 'Handlingar', + 'pageInfo' => 'Side {currentPage} av {pageCount}', + 'go_back' => 'Tilbake', + 'forms' => [ + 'editor' => [ + 'write' => 'Skriv', + 'preview' => 'Førehandsvising', + 'help' => 'Køyrer markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Trykk for å velja', + 'loadingText' => 'Lastar…', + 'noResultsText' => 'Fann ingen resultat', + 'noChoicesText' => 'Ingen val å velja mellom', + 'maxItemText' => 'Kan ikkje leggja til fleire element', + ], + 'upload_file' => 'Last opp ei fil', + 'remote_url' => 'Ekstern URL-adresse', + 'save' => 'Lagre', + ], + 'play_episode_button' => [ + 'play' => 'Spel', + 'playing' => 'Spelar', + ], + 'size_limit' => 'Maks storleik: {0}.', + 'choose_interact' => 'Vel korleis du vil samhandla', + 'view' => 'Vis', +]; diff --git a/modules/Admin/Language/nn-no/Countries.php b/modules/Admin/Language/nn-no/Countries.php new file mode 100644 index 00000000..451541ff --- /dev/null +++ b/modules/Admin/Language/nn-no/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Dei sameinte arabiske emirata', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua og Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarktis', + 'AR' => 'Argentina', + 'AS' => 'Amerikansk Samoa', + 'AT' => 'Austerrike', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland', + 'AZ' => 'Aserbajdsjan', + 'BA' => 'Bosnia og Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgia', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Sankt Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Den fleirnasjonale staten Bolivia', + 'BQ' => 'Bonaire, Sint Eustatius og Saba', + 'BR' => 'Brasil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet-øya', + 'BW' => 'Botswana', + 'BY' => 'Kviterussland', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Kokosøyane (Keelingøyane)', + 'CD' => 'Den demokratiske republikken Kongo', + 'CF' => 'Den sentralafrikanske republikken', + 'CG' => 'Kongo', + 'CH' => 'Sveits', + 'CI' => "Elfenbeinskysten", + 'CK' => 'Cook-øyane', + 'CL' => 'Chile', + 'CM' => 'Kamerun', + 'CN' => 'Kina', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Kapp Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmasøya', + 'CY' => 'Kypros', + 'CZ' => 'Tsjekkia', + 'DE' => 'Tyskland', + 'DJ' => 'Djibouti', + 'DK' => 'Danmark', + 'DM' => 'Dominica', + 'DO' => 'Den dominikanske republikken', + 'DZ' => 'Algerie', + 'EC' => 'Ecuador', + 'EE' => 'Estland', + 'EG' => 'Egypt', + 'EH' => 'Vest-Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spania', + 'ET' => 'Etiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falklandsøyane (Malvinas)', + 'FM' => 'Mikronesiaføderasjonen', + 'FO' => 'Færøyane', + 'FR' => 'Frankrike', + 'GA' => 'Gabon', + 'GB' => 'Storbritannia', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'Fransk Guyana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Grønland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Ekvatorialguinea', + 'GR' => 'Hellas', + 'GS' => 'Sør-Georgia og Sør-Sandwichøyane', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard- og McDonaldøyane', + 'HN' => 'Honduras', + 'HR' => 'Kroatia', + 'HT' => 'Haiti', + 'HU' => 'Ungarn', + 'ID' => 'Indonesia', + 'IE' => 'Irland', + 'IL' => 'Israel', + 'IM' => 'Man', + 'IN' => 'India', + 'IO' => 'Det britiske territoriet i Indiahavet', + 'IQ' => 'Irak', + 'IR' => 'Iran', + 'IS' => 'Island', + 'IT' => 'Italia', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kirgisistan', + 'KH' => 'Kambodsja', + 'KI' => 'Kiribati', + 'KM' => 'Komorane', + 'KN' => 'Saint Kitts og Nevis', + 'KP' => "Nord-Korea", + 'KR' => 'Sør-Korea', + 'KW' => 'Kuwait', + 'KY' => 'Cayman-øyane', + 'KZ' => 'Kasakhstan', + 'LA' => "Laos", + 'LB' => 'Libanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Litauen', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Marokko', + 'MC' => 'Monaco', + 'MD' => 'Moldova', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (fransk del)', + 'MG' => 'Madagaskar', + 'MH' => 'Marshall-øyane', + 'MK' => 'Den tidlegare jugoslaviske republikken Makedonia', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Nord-Marianane', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldivane', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mosambik', + 'N/A' => 'Ikkje relevant (lokal IP…)', + 'NA' => 'Namibia', + 'NC' => 'Ny-Kaledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolkøya', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Nederland', + 'NO' => 'Noreg', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Fransk Polynesia', + 'PG' => 'Papua Ny-Guinea', + 'PH' => 'Filippinane', + 'PK' => 'Pakistan', + 'PL' => 'Polen', + 'PM' => 'Saint Pierre og Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Den russiske føderasjonen', + 'RW' => 'Rwanda', + 'SA' => 'Saudi-Arabia', + 'SB' => 'Solomonøyane', + 'SC' => 'Seychellane', + 'SD' => 'Sudan', + 'SE' => 'Sverige', + 'SG' => 'Singapore', + 'SH' => 'St. Helena, Ascension og Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard og Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Surinam', + 'SS' => 'Sør-Sudan', + 'ST' => 'São Tomé og Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (nederlandsk del)', + 'SY' => 'Syria', + 'SZ' => 'Swaziland', + 'TC' => 'Turks- og Caicosøyane', + 'TD' => 'Tsjad', + 'TF' => 'Dei sørlege franske territoria', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tadsjikistan', + 'TK' => 'Tokelau', + 'TL' => 'Aust-Timor', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Tyrkia', + 'TT' => 'Trinidad og Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania', + 'UA' => 'Ukraina', + 'UG' => 'Uganda', + 'UM' => 'Dei mindre ytre øyane i USA', + 'US' => 'USA', + 'UY' => 'Uruguay', + 'UZ' => 'Usbekistan', + 'VA' => 'Vatikanstaten', + 'VC' => 'Sankt Vincent og Grenadinane', + 'VE' => 'Venezuela', + 'VG' => 'Dei britiske jomfruøyane', + 'VI' => 'Dei amerikanske jomfruøyane', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis og Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Mayotte', + 'ZA' => 'Sør-Afrika', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/nn-no/Dashboard.php b/modules/Admin/Language/nn-no/Dashboard.php new file mode 100644 index 00000000..cf1ee11a --- /dev/null +++ b/modules/Admin/Language/nn-no/Dashboard.php @@ -0,0 +1,28 @@ + 'Styringspanel', + 'welcome_message' => 'Velkomen til styrarområdet!', + 'podcasts' => [ + 'title' => 'Podkastar', + 'not_found' => 'Ingen publiserte podkastar', + 'last_published' => 'Sist lagt ut {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodar', + 'not_found' => 'Ingen publisert episode', + 'last_published' => 'Sist lagt ut {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Lagring', + 'subtitle' => '{totalUploaded} av {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/nn-no/Episode.php b/modules/Admin/Language/nn-no/Episode.php new file mode 100644 index 00000000..4e7bb526 --- /dev/null +++ b/modules/Admin/Language/nn-no/Episode.php @@ -0,0 +1,225 @@ + 'Sesong {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Sesong {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# kommentar} + other {# kommentarar} + }', + 'all_podcast_episodes' => 'Alle podkast-episodane', + 'back_to_podcast' => 'Gå tilbake til podkasten', + 'edit' => 'Rediger', + 'preview' => 'Førehandsvising', + 'publish' => 'Legg ut', + 'publish_edit' => 'Rediger publiseringa', + 'publish_date_edit' => 'Rediger publiseringsdatoen', + 'unpublish' => 'Avpubliser', + 'publish_error' => 'Episoden er allereie publisert.', + 'publish_edit_error' => 'Episoden er allereie publisert.', + 'publish_cancel_error' => 'Episoden er allereie publisert.', + 'publish_date_edit_error' => 'Episoden er ikkje lagt ut enno, så du kan ikkje endra publiseringsdatoen.', + 'publish_date_edit_future_error' => 'Du kan berre setja publiseringsdatoen til ein tidlegare dato. Viss du vil endra planlagd publisering, kan du avpublisera episoden fyrst.', + 'publish_date_edit_success' => 'Publiseringsdatoen er endra.', + 'unpublish_error' => 'Episoden er ikkje publisert.', + 'delete' => 'Slett', + 'go_to_page' => 'Gå til side', + 'create' => 'Legg til ein episode', + 'publication_status' => [ + 'published' => 'Lagt ut', + 'with_podcast' => 'Lagt ut', + 'scheduled' => 'Planlagt', + 'not_published' => 'Ikkje lagt ut', + ], + 'with_podcast_hint' => 'Skal gjevast ut samstundes som podkasten', + 'list' => [ + 'search' => [ + 'placeholder' => 'Søk etter ein episode', + 'clear' => 'Tøm søket', + 'submit' => 'Søk', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodar} + }', + 'episode' => 'Episode', + 'visibility' => 'Synlegheit', + 'downloads' => 'Nedlastingar', + 'comments' => 'Kommentarar', + 'actions' => 'Handlingar', + ], + 'messages' => [ + 'createSuccess' => 'Episoden er oppretta!', + 'editSuccess' => 'Episoden er oppdatert!', + 'publishSuccess' => '{publication_status, select, + published {Episoden er lagt ut.} + scheduled {Episoden er planlagt lagt ut.} + with_podcast {Denne episoden blir lagt ut samstundes som podkasten.} + other {Denne episoden er ikkje lagt ut.} + }', + 'publishCancelSuccess' => 'Du har avbrote å leggja ut episoden.', + 'unpublishBeforeDeleteTip' => 'Du må avpublisera episoden før du slettar han.', + 'scheduleDateError' => 'Du må velja publiseringsdato.', + 'deletePublishedEpisodeError' => 'Du må avpublisera episoden før du slettar han.', + 'deleteSuccess' => 'Episoden er sletta.', + 'deleteError' => 'Greidde ikkje sletta {type, select, + transcript {transkripsjon} + chapters {kapittel} + image {omslag} + audio {lyd} + other {media} + } for episoden.', + 'deleteFileError' => 'Greidde ikkje sletta {type, select, + transcript {transkripsjons} + chapters {kapittel} + image {omslags} + audio {lyd} + other {media} + }fila {file_key}. Du kan fjerna ho manuelt.', + 'sameSlugError' => 'Ei episode med denne kortadressa finst allereie.', + ], + 'form' => [ + 'file_size_error' => + 'Fila di er for stor! Maks filstorleik er {0}. Auk `memory_limit`, `upload_max_filesize` og `post_max_size`-verdiane i php-oppsettsfila di og start omatt vevtenaren din for å lasta opp fila di.', + 'audio_file' => 'Lydfil', + 'audio_file_hint' => 'Vel ei .mp3- eller .m4a-lydfil.', + 'info_section_title' => 'Episodeinfo', + 'cover' => 'Episodeomslag', + 'cover_hint' => + 'Viss du ikkje bruker eige omslag, blir omslaget til podkasten brukt i staden.', + 'cover_size_hint' => 'Omslaget må vera kvadratisk, og minst 1400pkt breitt og høgt.', + 'title' => 'Tittel', + 'title_hint' => + 'Bør innehalda eit klårt og konsist episodenamn. Ikkje skriv inn nummer på episode eller sesong her.', + 'permalink' => 'Fastlenke', + 'season_number' => 'Sesong', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Fullstendig innhald (episoden)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Kort stykke med blestingsinnhald som representerer denne episoden', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Ekstra innhald (til dømes bakominfo eller intervju med skodespelarane) eller innhald for å framheva ein annan serie', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episoden må vera tilgjengeleg berre for premium-abonnentar', + 'parental_advisory' => [ + 'label' => 'Råd til foreldre', + 'hint' => 'Inneheld episoden grov prat?', + 'undefined' => 'udefinert', + 'clean' => 'Familievenleg', + 'explicit' => 'Grovt', + ], + 'show_notes_section_title' => 'Vis notat', + 'show_notes_section_subtitle' => + 'Opp til 4000 teikn. Ver tydeleg og konsis. Skriv notat som hjelper lyttarane å finna episoden.', + 'description' => 'Skildring', + 'description_footer' => 'Botntekst for skildringa', + 'description_footer_hint' => + 'Denne teksten ligg på slutten av kvar episodeskildring, og er ein god stad å ha lenker til td. sosiale nettverk.', + 'additional_files_section_title' => 'Fleire filer', + 'additional_files_section_subtitle' => + 'Desse filene kan brukast av andre plattformer for å gje publikum ei betre oppleving. Sjå {podcastNamespaceLink} for meir informasjon.', + 'location_section_title' => 'Stad', + 'location_section_subtitle' => 'Kva stad handlar denne episoden om?', + 'location_name' => 'Stadnamn eller adresse', + 'location_name_hint' => 'Dette kan vera ein verkeleg eller oppdikta stad', + 'transcript' => 'Transkribering (undertitlar eller teksting)', + 'transcript_hint' => 'Berre .srt eller .vtt er lov.', + 'transcript_download' => 'Last ned transkriberinga', + 'transcript_file' => 'Transkriberingsfil (.srt eller .vtt)', + 'transcript_remote_url' => 'Ekstern URL for teksting', + 'transcript_file_delete' => 'Slett transkriberingsfila', + 'chapters' => 'Kapittel', + 'chapters_hint' => 'Fila må vera i JSON-kapittelformat.', + 'chapters_download' => 'Last ned kapittel', + 'chapters_file' => 'Kapittelfil', + 'chapters_remote_url' => 'Ekstern URL til kapittelfil', + 'chapters_file_delete' => 'Slett kapittelfila', + 'advanced_section_title' => 'Avanserte innstillingar', + 'advanced_section_subtitle' => + 'Viss du treng RSS-merkelappar som Castopod ikkje handterer, kan du skriva dei inn her.', + 'custom_rss' => 'Eigne RSS-merkelappar for episoden', + 'custom_rss_hint' => 'Dette blir sett inn i ❬item❭-elementet.', + 'block' => 'Episoden skal gøymast frå offentlege katalogar', + 'block_hint' => + 'Vis- eller gøym- status for episoden: Dersom du skrur på dette, hindrar det at episoden kjem opp i Apple podcasts, Google podcasts og andre tredjeparts-appar som hentar podkastar frå desse (men ingen garanti)', + 'submit_create' => 'Lag episode', + 'submit_edit' => 'Lagre episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Tilbake til episodeoversikta', + 'post' => 'Kunngjeringsinnlegget ditt', + 'post_hint' => + "Skriv ei melding for å kunngjera at du har lagt ut episoden din. Meldinga blir kringkasta til alle fylgjarane dine på fødiverset, og vil stå på heimesida til podkasten din.", + 'message_placeholder' => 'Skriv meldinga…', + 'publication_date' => 'Publiseringsdato', + 'publication_method' => [ + 'now' => 'No', + 'schedule' => 'Planlegg', + 'with_podcast' => 'Legg ut saman med podkast', + ], + 'scheduled_publication_date' => 'Planlagt publiseringsdato', + 'scheduled_publication_date_clear' => 'Tøm publiseringsdatoen', + 'scheduled_publication_date_hint' => + 'Du kan planleggja å offengleggjera episoden seinare ved å skriva inn eit publiseringstidspunkt. Feltet må vera i formatet ÅÅÅÅ-MM-DD HH:mm', + 'submit' => 'Legg ut', + 'submit_edit' => 'Rediger publiseringa', + 'cancel_publication' => 'Avbryt publisering', + 'message_warning' => 'Du skreiv inga melding til kunngjeringsinnlegget ditt!', + 'message_warning_hint' => 'Viss du skriv ei melding, kan det gje meir sosialt engasjement og syta for at episoden din blir meir synleg.', + 'message_warning_submit' => 'Legg ut likevel', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Ny publiseringsdato', + 'new_publication_date_hint' => 'Må vera ein dato i fortida.', + 'submit' => 'Rediger publiseringsdatoen', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Viss du avpubliserer episoden, slettar du alle kommentarar og innlegg til han, og fjernar han frå RSS-straumen til podkasten.", + 'understand' => 'Eg forstår, eg vil avpublisera episoden', + 'submit' => 'Avpubliser', + ], + 'delete_form' => [ + 'disclaimer' => + "Viss du slettar episoden, slettar du òg alle tilknytte mediafiler, kommentarar, filmklypp og lydbetar.", + 'understand' => 'Eg forstår, eg vil sletta episoden', + 'submit' => 'Slett', + ], + 'embed' => [ + 'title' => 'Innbyggbar spelar', + 'label' => + 'Vel eit fargetema, kopier den innbyggbare spelaren til utklyppstavla og lim han inn på nettstaden din.', + 'clipboard_iframe' => 'Kopier den innbyggbare spelaren til utklyppstavla', + 'clipboard_url' => 'Kopier adressa til utklyppstavla', + 'dark' => 'Mørk', + 'dark-transparent' => 'Mørk gjennomsiktig', + 'light' => 'Lys', + 'light-transparent' => 'Lys gjennomsiktig', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'kladdemodus', + 'text' => '{publication_status, select, + published {Episoden er ikkje lagt ut enno.} + scheduled {Episoden er planlagt lagt ut på {publication_date}.} + with_podcast {Denne episoden blir lagt ut samstundes som podkasten.} + other {Denne episoden er ikkje lagt ut enno.} + }', + 'preview' => 'Førehandsvising', + ], +]; diff --git a/modules/Admin/Language/nn-no/EpisodeNavigation.php b/modules/Admin/Language/nn-no/EpisodeNavigation.php new file mode 100644 index 00000000..e0bf8199 --- /dev/null +++ b/modules/Admin/Language/nn-no/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Vis episode-sida', + 'dashboard' => 'Episodestyringspanelet', + 'episode-view' => 'Heim', + 'episode-edit' => 'Rediger episoden', + 'episode-persons-manage' => 'Handter personar', + 'embed-add' => 'Innbyggbar spelar', + 'clips' => 'Klypp', + 'video-clips-list' => 'Videoklypp', + 'video-clips-create' => 'Nytt videoklypp', + 'soundbites-list' => 'Lydbetar', + 'soundbites-create' => 'Ny lydbete', +]; diff --git a/modules/Admin/Language/nn-no/Fediverse.php b/modules/Admin/Language/nn-no/Fediverse.php new file mode 100644 index 00000000..1b136b74 --- /dev/null +++ b/modules/Admin/Language/nn-no/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Fann ikkje kontoen!', + 'blockActorSuccess' => '{actor} er blokkert!', + 'unblockActorSuccess' => 'Aktøren er avblokkert!', + 'blockDomainSuccess' => '{domain} er blokkert!', + 'unblockDomainSuccess' => '{domain} er avblokkert!', + ], + 'blocked_actors' => 'Blokkerte kontoar', + 'blocked_domains' => 'Blokkerte domene', + 'block_lists_form' => [ + 'handle' => 'Kontohandtak', + 'handle_hint' => 'Skriv inn ein @brukarnamn@domene-konto.', + 'domain' => 'Domenenamn', + 'submit' => 'Blokker!', + ], + 'list' => [ + 'actor' => 'Konto', + 'domain' => 'Domenenamn', + 'unblock' => 'Avblokker', + ], +]; diff --git a/modules/Admin/Language/nn-no/Home.php b/modules/Admin/Language/nn-no/Home.php new file mode 100644 index 00000000..3ef47501 --- /dev/null +++ b/modules/Admin/Language/nn-no/Home.php @@ -0,0 +1,14 @@ + 'Alle podkastar', + 'no_podcast' => 'Fann ingen podkast', +]; diff --git a/modules/Admin/Language/nn-no/Install.php b/modules/Admin/Language/nn-no/Install.php new file mode 100644 index 00000000..fefcb365 --- /dev/null +++ b/modules/Admin/Language/nn-no/Install.php @@ -0,0 +1,61 @@ + 'Manuelt oppsett', + 'manual_config_subtitle' => + 'Lag ei `.env`-fil med innstillingane dine og oppdater sida for å halda fram installasjonen.', + 'form' => [ + 'instance_config' => 'Oppsett for nettstaden', + 'hostname' => 'Vertsnamn', + 'media_base_url' => 'Mediabase-URL', + 'media_base_url_hint' => + 'Viss du bruker eit leveringsnettverk (CDN) og/eller ei ekstern analysetenest, kan du skriva dei inn her.', + 'admin_gateway' => 'Innfallsport for styrar', + 'admin_gateway_hint' => + 'Ruta for å koma til styringsområdet (td. https://eksempel.no/cp-admin). Standardvalet er cp-admin, me tilrår at du endrar det av omsyn til tryggleiken.', + 'auth_gateway' => 'Innfallsport for autentisering', + 'auth_gateway_hint' => + 'Ruta for å koma til autentiseringssidene (td. https://eksempel.no/cp-auth). Standardvalet er cp-auth, me tilrår at du endrar det av omsyn til tryggleiken.', + 'database_config' => 'Databaseoppsett', + 'database_config_hint' => + 'Castopod treng å kopla seg til MySQL (eller MariaDB)-databasen din. Viss du ikkje har opplysingane som trengst, må du kontakta systemansvarleg.', + 'db_hostname' => 'Databasevertsnamn', + 'db_name' => 'Databasenamn', + 'db_username' => 'Databasebrukarnamn', + 'db_password' => 'Databasepassord', + 'db_prefix' => 'Databaseprefiks', + 'db_prefix_hint' => + "Prefikset til Castopod-tabellane. La det stå om du ikkje veit kva det tyder.", + 'cache_config' => 'Mellomlagringsoppsett', + 'cache_config_hint' => + 'Vel korleis du vil handtera mellomlageret. La stå som det er om du ikkje veit kva det tyder.', + 'cache_handler' => 'Mellomlagerhandtering', + 'cacheHandlerOptions' => [ + 'file' => 'Fil', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Neste', + 'submit' => 'Fullfør installeringa', + 'create_superadmin' => 'Lag superstyrar-konto', + 'email' => 'Epost', + 'username' => 'Brukarnamn', + 'password' => 'Passord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Superstyrar-kontoen din er oppretta. Logg inn for å byrja med podkasting!', + 'databaseConnectError' => + 'Castopod greidde ikkje å kopla til databasen din. Sjå gjennom databaseoppsettet og prøv ein gong til.', + 'writeError' => + "Greidde ikkje laga eller skriva til `.env`-fila. Du må laga ho manuelt ved å fylgja `.env.example`-filmalen i Castopod-pakka.", + ], +]; diff --git a/modules/Admin/Language/nn-no/Navigation.php b/modules/Admin/Language/nn-no/Navigation.php new file mode 100644 index 00000000..d7101730 --- /dev/null +++ b/modules/Admin/Language/nn-no/Navigation.php @@ -0,0 +1,44 @@ + 'Vis/gøym sidepanelet', + 'go_to_website' => 'Gå til nettsida', + 'go_to_admin' => 'Gå til styringspanelet', + 'not-authorized' => 'Ikkje godkjent', + 'dashboard' => 'Styringspanel', + 'admin' => 'Heim', + 'podcasts' => 'Podkastar', + 'podcast-list' => 'Alle podkastar', + 'podcast-create' => 'Ny podkast', + 'all-podcast-imports' => 'Alle podkast-importar', + 'podcast-imports-add' => 'Importer ein podkast', + 'persons' => 'Personar', + 'person-list' => 'Alle personar', + 'person-create' => 'Ny person', + 'fediverse' => 'Fødiverset', + 'fediverse-blocked-actors' => 'Blokkerte kontoar', + 'fediverse-blocked-domains' => 'Blokkerte domene', + 'users' => 'Brukarar', + 'user-list' => 'Alle brukarane', + 'user-create' => 'Ny brukar', + 'pages' => 'Sider', + 'page-list' => 'Alle sidene', + 'page-create' => 'Ny side', + 'settings' => 'Innstillingar', + 'settings-general' => 'Generelt', + 'settings-theme' => 'Bunad', + 'admin-about' => 'Om', + 'account' => [ + 'my-account' => 'Kontoen min', + 'change-password' => 'Endre passord', + 'logout' => 'Logg ut', + ], +]; diff --git a/modules/Admin/Language/nn-no/Notifications.php b/modules/Admin/Language/nn-no/Notifications.php new file mode 100644 index 00000000..0ff8568b --- /dev/null +++ b/modules/Admin/Language/nn-no/Notifications.php @@ -0,0 +1,19 @@ + 'Varslingar', + 'reply' => '{actor_username} svara på innlegget ditt', + 'favourite' => '{actor_username} merkte innlegget ditt som favoritt', + 'reblog' => '{actor_username} delte innlegget ditt', + 'follow' => '{actor_username} fylgde deg', + 'no_notifications' => 'Ingen varslingar', + 'mark_all_as_read' => 'Merk alle som lesne', +]; diff --git a/modules/Admin/Language/nn-no/Page.php b/modules/Admin/Language/nn-no/Page.php new file mode 100644 index 00000000..3533de52 --- /dev/null +++ b/modules/Admin/Language/nn-no/Page.php @@ -0,0 +1,30 @@ + 'Heimatt', + 'page' => 'Side', + 'all_pages' => 'Alle sidene', + 'create' => 'Ny side', + 'go_to_page' => 'Gå til side', + 'edit' => 'Rediger sida', + 'delete' => 'Slett sida', + 'form' => [ + 'title' => 'Tittel', + 'permalink' => 'Fastlenke', + 'content' => 'Innhald', + 'submit_create' => 'Lag side', + 'submit_edit' => 'Lagre', + ], + 'messages' => [ + 'createSuccess' => 'Sida “{pageTitle}” er oppretta!', + 'editSuccess' => 'Sida er oppdatert!', + ], +]; diff --git a/modules/Admin/Language/nn-no/Pager.php b/modules/Admin/Language/nn-no/Pager.php new file mode 100644 index 00000000..5b135b32 --- /dev/null +++ b/modules/Admin/Language/nn-no/Pager.php @@ -0,0 +1,21 @@ + 'Sidenavigering', + 'first' => 'Fyrste', + 'previous' => 'Førre', + 'next' => 'Neste', + 'last' => 'Siste', + 'older' => 'Eldre', + 'newer' => 'Nyare', + 'invalidTemplate' => '{0} er ikkje ein gyldig sidenavigeringsmal.', + 'invalidPaginationGroup' => '{0} er ikkje ei gyldig pagineringsgruppe.', +]; diff --git a/modules/Admin/Language/nn-no/Person.php b/modules/Admin/Language/nn-no/Person.php new file mode 100644 index 00000000..33578a54 --- /dev/null +++ b/modules/Admin/Language/nn-no/Person.php @@ -0,0 +1,65 @@ + 'Personar', + 'all_persons' => 'Alle personar', + 'no_person' => 'Fann ingen!', + 'create' => 'Lag ein person', + 'view' => 'Sjå personen', + 'edit' => 'Rediger personen', + 'delete' => 'Slett personen', + 'messages' => [ + 'createSuccess' => 'Personen er oppretta!', + 'editSuccess' => 'Personen er oppdatert!', + 'deleteSuccess' => 'Personen er fjerna!', + ], + 'form' => [ + 'avatar' => 'Profilbilete', + 'avatar_size_hint' => + 'Profilbiletet må vera kvadratisk og minst 400pkt breitt og høgt.', + 'full_name' => 'Fullt namn', + 'full_name_hint' => 'Dette er det fulle namnet eller aliaset til personen.', + 'unique_name' => 'Unikt namn', + 'unique_name_hint' => 'Brukt til URL-ar', + 'information_url' => 'Informasjons-URL', + 'information_url_hint' => + 'URL til ei relevant side med opplysingar om personen, slik som ei heimeside eller ei profilside hjå ein tredjepart.', + 'submit_create' => 'Lag person', + 'submit_edit' => 'Lagre person', + ], + 'podcast_form' => [ + 'title' => 'Handter personar', + 'add_section_title' => 'Legg personar til denne podkasten', + 'add_section_subtitle' => 'Du kan velja fleire personar og roller.', + 'persons' => 'Personar', + 'persons_hint' => + 'Du kan velja ein eller fleire personar med same roller. Du må laga personane fyrst.', + 'roles' => 'Roller', + 'roles_hint' => + 'Du kan velja ingen, ei eller fleire roller for ein person.', + 'submit_add' => 'Legg til person(ar)', + 'remove' => 'Fjern', + ], + 'episode_form' => [ + 'title' => 'Handter personar', + 'add_section_title' => 'Legg personar til denne episoden', + 'add_section_subtitle' => 'Du kan velja fleire personar og roller.', + 'persons' => 'Personar', + 'persons_hint' => + 'Du kan velja ein eller fleire personar med same roller. Du må laga personane fyrst.', + 'roles' => 'Roller', + 'roles_hint' => + 'Du kan velja ingen, ei eller fleire roller for ein person.', + 'submit_add' => 'Legg til person(ar)', + 'remove' => 'Fjern', + ], + 'credits' => 'Bidragsytarar', +]; diff --git a/modules/Admin/Language/nn-no/Platforms.php b/modules/Admin/Language/nn-no/Platforms.php new file mode 100644 index 00000000..5d1e2a75 --- /dev/null +++ b/modules/Admin/Language/nn-no/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podkastplattformer', + 'social' => 'Sosiale nettverk', + 'funding' => 'Donasjonslenker', + ], + 'website' => 'Nettside', + 'home_url' => 'Gå til {platformName}-nettstaden', + 'register' => 'Registrer deg', + 'submit_url' => 'Send podkasten din til {platformName}', + 'your_link' => 'Lenka di', + 'your_id' => [ + 'podcasting' => 'ID-en din', + 'social' => 'ID-en din', + 'funding' => 'Lokkeordet ditt', + ], + 'your_cta' => 'Lokkeordet ditt', + 'visible' => 'Vis på heimesida til podkasten?', + 'on_embed' => 'Vis i den innbyggbare spelaren?', + 'remove' => 'Fjern {platformName}', + 'submit' => 'Lagre', + 'messages' => [ + 'updateSuccess' => 'Plattformlenkene er oppdaterte!', + 'removeLinkSuccess' => 'Plattformlenka er fjerna.', + 'removeLinkError' => + 'Greidde ikkje fjerna plattformlenka. Prøv ein gong til.', + ], + 'description' => [ + 'podcasting' => 'Podkast-IDen på denne plattforma', + 'social' => 'Konto-IDen til podkastane på denne plattforma', + 'funding' => 'Oppmodingsmelding', + ], +]; diff --git a/modules/Admin/Language/nn-no/Podcast.php b/modules/Admin/Language/nn-no/Podcast.php new file mode 100644 index 00000000..18ef937e --- /dev/null +++ b/modules/Admin/Language/nn-no/Podcast.php @@ -0,0 +1,330 @@ + 'Alle podkastar', + 'no_podcast' => 'Fann ingen podkast!', + 'create' => 'Lag ein podcast', + 'import' => 'Importer ein podkast', + 'all_imports' => 'Podkast-importar', + 'new_episode' => 'Ny episode', + 'view' => 'Sjå podkasten', + 'edit' => 'Rediger podkasten', + 'publish' => 'Legg ut podkasten', + 'publish_edit' => 'Rediger publiseringa', + 'delete' => 'Slett podkasten', + 'see_episodes' => 'Sjå episodane', + 'see_contributors' => 'Sjå bidragsytarane', + 'monetization_other' => 'Andre måtar å tena pengar på', + 'go_to_page' => 'Gå til side', + 'latest_episodes' => 'Dei nyaste episodane', + 'see_all_episodes' => 'Sjå alle episodane', + 'draft' => 'Kladd', + 'messages' => [ + 'createSuccess' => 'Podkasten er oppretta!', + 'editSuccess' => 'Podkasten er oppdatert!', + 'importSuccess' => 'Podkasten er importert!', + 'deleteSuccess' => 'Podkasten @{podcast_handle} vart sletta.', + 'deletePodcastMediaError' => 'Greidde ikkje sletta {type, select, + cover {omslaget} + banner {banneret} + other {media} + } til podkasten.', + 'deleteEpisodeMediaError' => 'Greidde ikkje sletta {type, select, + transcript {transkripsjonen} + chapters {kapittel} + image {omslag} + audio {lyd} + other {media} + } frå {episode_slug}.', + 'deletePodcastMediaFolderError' => 'Greidde ikkje sletta mediemappa {folder_path} for podkasten. Du kan sletta mappa manuelt.', + 'podcastFeedUpdateSuccess' => 'Vellukka oppdatering: {number_of_new_episodes, plural, + one {# episode vart lagt} + other {# episodar vart lagde} + } til podkasten!', + 'podcastFeedUpToDate' => 'Podkasten er allereie oppdatert.', + 'publishError' => 'Denne podkasten er allereie lagt ut eller planlagt for offentleggjering.', + 'publishEditError' => 'Denne podkasten er ikkje planlagt publisert.', + 'publishCancelSuccess' => 'Du har avbrote å leggja ut podkasten.', + 'scheduleDateError' => 'Du må velja publiseringsdato.', + ], + 'form' => [ + 'identity_section_title' => 'Podkastidentitet', + 'identity_section_subtitle' => 'Desse felta gjer at du blir lagt merke til.', + 'fediverse_section_title' => 'Allheim-identitet', + + 'cover' => 'Podkastomslag', + 'cover_size_hint' => 'Omslaget må vera kvadratisk, og minst 1400pkt breitt og høgt.', + 'banner' => 'Podkastbanner', + 'banner_size_hint' => 'Banneret må ha 3:1-forhold og vera minst 1500pkt breitt.', + 'banner_delete' => 'Slett podkastbanneret', + 'title' => 'Tittel', + 'handle' => 'Handtak', + 'handle_hint' => + 'Blir brukt til å identifisera podkasten. Du kan bruka store og små bokstavar, tal og understrek.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Med episodar', + 'episodic_hint' => 'Viss det er meininga at episodane skal kunna lyttast til uansett rekkjefylgje. Dei nyaste episodane blir presenterte fyrst.', + 'serial' => 'I serie', + 'serial_hint' => 'Om det er meininga at episodane skal koma i ei bestemt rekkjefylgje. Episodane med lågast nummer blir presenterte fyrst.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium slik det blir vist av podcast:medium-merkelappen i RSS. Viss du endrar dette, kan det påverka korleis avspelarar viser straumen din.', + 'podcast' => 'Podkast', + 'podcast_hint' => 'Skildrar ein straum for eit podkast-show.', + 'music' => 'Musikk', + 'music_hint' => 'Ein straum med musikk organisert i eit "album" der kvart element er ein song på albumet.', + 'audiobook' => 'Lydbok', + 'audiobook_hint' => 'Spesifikke typar lyd med eit element per straum, eller der elementa er kapittel i boka.', + ], + 'description' => 'Skildring', + 'classification_section_title' => 'Klassifisering', + 'classification_section_subtitle' => + 'Desse felta vil påverka publikummet og konkurransen din.', + 'language' => 'Språk', + 'category' => 'Kategori', + 'category_placeholder' => 'Vel ein kategori…', + 'other_categories' => 'Andre kategoriar', + 'parental_advisory' => [ + 'label' => 'Råd til foreldre', + 'hint' => 'Er det grov prat her?', + 'undefined' => 'udefinert', + 'clean' => 'Familievenleg', + 'explicit' => 'Grovt', + ], + 'author_section_title' => 'Forfattar', + 'author_section_subtitle' => 'Kven styrer podkasten?', + 'owner_name' => 'Namn på eigaren', + 'owner_name_hint' => + 'Berre til administrativ bruk. Synleg i den offentlege RSS-straumen.', + 'owner_email' => 'Epost til eigaren', + 'owner_email_hint' => + 'Blir brukt av dei fleste plattformer til å stadfesta eigarskapen til podkasten. Synleg i den offentlege RSS-straumen.', + 'is_owner_email_removed_from_feed' => 'Fjernar eposten til eigaren frå den offentlege RSS-straumen', + 'is_owner_email_removed_from_feed_hint' => 'Det kan henda du mellombels må visa eposten din slik at ei katalogtenest kan stadfesta at du eig podkasten.', + 'publisher' => 'Utgjevar', + 'publisher_hint' => + 'Gruppa som er ansvarleg for serien. Det er vanlegvis morselskapet eller nettverket til ein podkast. Dette feltet er stundom merka med «forfattar».', + 'copyright' => 'Opphavsrett', + 'location_section_title' => 'Stad', + 'location_section_subtitle' => 'Kva stad handlar denne podkasten om?', + 'location_name' => 'Stadnamn eller adresse', + 'location_name_hint' => 'Dette kan vera ein verkeleg eller oppdikta stad', + 'monetization_section_title' => 'Kommersialisering', + 'monetization_section_subtitle' => + 'Ten pengar med hjelp frå publikummet ditt.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodane må ha premium som standardval', + 'premium_by_default_hint' => 'Podkastepisodane vil få premium som standardmerking. Du kan likevel ha nokre episodar, trailerar eller bonusar som offentlege.', + 'op3' => 'Open Podcast Prefix-prosjekt (OP3)', + 'op3_link' => 'Gå til OP3-styringspanelet ditt (ekstern lenke)', + 'op3_hint' => 'Verdiset analysedataa dine med OP3, som er ein tredjeparts analyseteneste med open kjeldekode. Del, stadfest og samanlikne analysedataa dine med det opne podkast-økosystemet.', + 'op3_enable' => 'Bruk OP3-analysetenesta', + 'op3_enable_hint' => 'Av tryggleiksgrunnar deler me ikkje analysedata for premium-episodar med OP3.', + 'payment_pointer' => 'Betalingspunkt for nettkommersialisering', + 'payment_pointer_hint' => + 'Det er her du vil få inn pengar frå nettkommersialiseringa', + 'advanced_section_title' => 'Avanserte innstillingar', + 'advanced_section_subtitle' => + 'Viss du treng RSS-merkelappar som Castopod ikkje handterer, kan du skriva dei inn her.', + 'custom_rss' => 'Eigne RSS-merkelappar for podkasten', + 'custom_rss_hint' => 'Dette blir sett inn i ❬channel❭-elementet.', + 'verify_txt' => 'Stadfesting av eigarskap TXT', + 'verify_txt_hint' => 'I staden for å bruka epost, kan nokre tredjepartstenester stadfesta at du eig podkasten ved å be deg setja inn ein godkjenningstekst i straumen din.', + 'verify_txt_helper' => 'Denne teksten blir sett inn i ein -knagg.', + 'new_feed_url' => 'Ny straum-URL', + 'new_feed_url_hint' => 'Bruk dette feltet når du flyttar til eit anna domene eller vertsplattform. Standardvalet for verdien er den noverande RSS-adresse viss podkasten er importert.', + 'old_feed_url' => 'Gamal straum-URL', + 'partnership' => 'Partnarskap', + 'partner_id' => 'ID', + 'partner_link_url' => 'Lenke-URL', + 'partner_image_url' => 'Bilet-URL', + 'partner_id_hint' => 'Din eigen partnar-ID', + 'partner_link_url_hint' => 'Lenkeadressa til den generelle partnaren', + 'partner_image_url_hint' => 'Biletadressa til den generelle partnaren', + 'block' => 'Podkasten skal gøymast frå offentlege katalogar', + 'block_hint' => + 'Vis- eller gøym- status for podkasten: Dersom du skrur på dette, hindrar det heile podkasten frå å syna i Apple podcasts, Google podcasts og andre tredjeparts-appar som hentar podkastar frå desse (men ingen garanti)', + 'complete' => 'Podkasten vil ikkje få fleire episodar', + 'lock' => 'Hindre at podkasten blir kopiert', + 'lock_hint' => + 'Føremålet er å fortelja andre podkastplattformer om dei kan importera denne straumen. Dersom verdien er ja, blir alle forsøk på å importera denne straumen til ei ny plattform nekta.', + 'submit_create' => 'Lag podkast', + 'submit_edit' => 'Lagre podkasten', + ], + 'category_options' => [ + 'uncategorized' => 'ukategorisert', + 'arts' => 'Kunst', + 'business' => 'Forretningar', + 'comedy' => 'Komedie', + 'education' => 'Utdanning', + 'fiction' => 'Fiksjon', + 'government' => 'Styresmakter', + 'health_and_fitness' => 'Helse og trening', + 'history' => 'Historie', + 'kids_and_family' => 'Born & familie', + 'leisure' => 'Fritid', + 'music' => 'Musikk', + 'news' => 'Nytt', + 'religion_and_spirituality' => 'Religion & spiritualitet', + 'science' => 'Vitskap', + 'society_and_culture' => 'Samfunn & kultur', + 'sports' => 'Idrett', + 'technology' => 'Teknologi', + 'true_crime' => 'Sann krim', + 'tv_and_film' => 'TV & film', + 'books' => 'Bøker', + 'design' => 'Design', + 'fashion_and_beauty' => 'Mote & venleik', + 'food' => 'Mat', + 'performing_arts' => 'Utøvande kunst', + 'visual_arts' => 'Visuell kunst', + 'careers' => 'Karriere', + 'entrepreneurship' => 'Entreprenørskap', + 'investing' => 'Investering', + 'management' => 'Leiing', + 'marketing' => 'Marknadsføring', + 'non_profit' => 'Friviljug arbeid', + 'comedy_interviews' => 'Humor-intervju', + 'improv' => 'Improvisasjon', + 'stand_up' => 'Ståkomikk', + 'courses' => 'Kurs', + 'how_to' => 'Slik gjer du', + 'language_learning' => 'Språklæring', + 'self_improvement' => 'Sjølvforbetring', + 'comedy_fiction' => 'Oppdikta humor', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternativ helse', + 'fitness' => 'Kom i form', + 'medicine' => 'Medisin', + 'mental_health' => 'Mental helse', + 'nutrition' => 'Næring', + 'sexuality' => 'Seksualitet', + 'education_for_kids' => 'Utdanning for born', + 'parenting' => 'Oppseding', + 'pets_and_animals' => 'Kjæledyr & dyr', + 'stories_for_kids' => 'Historier for born', + 'animation_and_manga' => 'Animasjon & manga', + 'automotive' => 'Bil og motor', + 'aviation' => 'Luftfart', + 'crafts' => 'Handverk', + 'games' => 'Spel', + 'hobbies' => 'Hobbyar', + 'home_and_garden' => 'Heim og hage', + 'video_games' => 'Videospel', + 'music_commentary' => 'Musikkommentarar', + 'music_history' => 'Musikkhistorie', + 'music_interviews' => 'Musikkintervju', + 'business_news' => 'Handelsnytt', + 'daily_news' => 'Dagleg nytt', + 'entertainment_news' => 'Underhaldningsnytt', + 'news_commentary' => 'Kommentarar til nyhende', + 'politics' => 'Politikk', + 'sports_news' => 'Sportsnytt', + 'tech_news' => 'Teknologinytt', + 'buddhism' => 'Buddhisme', + 'christianity' => 'Kristendom', + 'hinduism' => 'Hinduisme', + 'islam' => 'Islam', + 'judaism' => 'Jødedom', + 'religion' => 'Religion', + 'spirituality' => 'Spiritualitet', + 'astronomy' => 'Astronomi', + 'chemistry' => 'Kjemi', + 'earth_sciences' => 'Geofag', + 'life_sciences' => 'Humaniora', + 'mathematics' => 'Matematikk', + 'natural_sciences' => 'Naturvitskap', + 'nature' => 'Natur', + 'physics' => 'Fysisk', + 'social_sciences' => 'Sosialfag', + 'documentary' => 'Dokumentar', + 'personal_journals' => 'Personlege journalar', + 'philosophy' => 'Filosofi', + 'places_and_travel' => 'Stader & reise', + 'relationships' => 'Forhold', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasiidrettar', + 'football' => 'Fotball', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Springing', + 'soccer' => 'Fotball', + 'swimming' => 'Symjing', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Villmark', + 'wrestling' => 'Bryting', + 'after_shows' => 'Etterprogram', + 'film_history' => 'Filmhistorie', + 'film_interviews' => 'Filmintervju', + 'film_reviews' => 'Filmmeldingar', + 'tv_reviews' => 'TV-meldingar', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Tilbake til podkast-styringspanelet', + 'post' => 'Kunngjeringsinnlegget ditt', + 'post_hint' => + "Skriv ei melding for å kunngjera at du legg ut podkasten. Dette vil stå på hiemesida til podkasten din.", + 'message_placeholder' => 'Skriv kunngjeringa di…', + 'submit' => 'Legg ut', + 'publication_date' => 'Publiseringsdato', + 'publication_method' => [ + 'now' => 'No', + 'schedule' => 'Tidsplan', + ], + 'scheduled_publication_date' => 'Planlagd publiseringsdato', + 'scheduled_publication_date_hint' => + 'Du kan planleggja å offengleggjera podkasten seinare ved å skriva inn eit publiseringstidspunkt. Feltet må vera i formatet ÅÅÅÅ-MM-DD HH:mm', + 'submit_edit' => 'Rediger publiseringa', + 'cancel_publication' => 'Avbryt publisering', + 'message_warning' => 'Du skreiv inga melding til kunngjeringsinnlegget ditt!', + 'message_warning_hint' => 'Viss du skriv ei melding, kan det gje meir sosialt engasjement og syta for at podkasten din blir meir synleg.', + 'message_warning_submit' => 'Legg ut likevel', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'kladdemodus', + 'not_published' => 'Denne podkasten er ikkje lagt ut enno.', + 'scheduled' => 'Denne podkasten er planlagt for utgjeving {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Viss du slettar podkasten, vil det sletta alle episodar, mediafiler, innlegg og analyse som høyrer til. Du kan ikkje angra dette, og vil ikkje få det tilbake etterpå.", + 'understand' => 'Eg forstår, og vil sletta podkasten for alltid', + 'submit' => 'Slett', + ], + 'by' => 'Av {publisher}', + 'season' => 'Sesong {seasonNumber}', + 'list_of_episodes_year' => '{year}-episodar ({episodeCount})', + 'list_of_episodes_season' => + 'Sesong {seasonNumber}-episodar ({episodeCount})', + 'no_episode' => 'Fann ingen episode!', + 'follow' => 'Fylg', + 'followers' => '{numberOfFollowers, plural, + one {# fylgjar} + other {# fylgjarar} + }', + 'posts' => '{numberOfPosts, plural, + one {# innlegg} + other {# innlegg} + }', + 'activity' => 'Aktivitet', + 'episodes' => 'Episodar', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Finansieringslenker for {podcastTitle}', + 'find_on' => 'Finn {podcastTitle} på', + 'listen_on' => 'Høyr på', +]; diff --git a/modules/Admin/Language/nn-no/PodcastNavigation.php b/modules/Admin/Language/nn-no/PodcastNavigation.php new file mode 100644 index 00000000..301692bd --- /dev/null +++ b/modules/Admin/Language/nn-no/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Gå til podkastsida', + 'rss_feed' => 'RSS-straum', + 'dashboard' => 'Podkast-styringspanel', + 'podcast-view' => 'Heim', + 'podcast-edit' => 'Rediger podkasten', + 'podcast-persons-manage' => 'Handter personar', + 'podcast-imports' => 'Podkast-importar', + 'podcast-imports-sync' => 'Synkroniser straumar', + 'episodes' => 'Episodar', + 'episode-list' => 'Alle episodane', + 'episode-create' => 'Ny episode', + 'analytics' => 'Analysar', + 'podcast-analytics' => 'Oversikt over publikum', + 'podcast-analytics-webpages' => 'Nettsidevisingar', + 'podcast-analytics-locations' => 'Stader', + 'podcast-analytics-unique-listeners' => 'Unike lyttarar', + 'podcast-analytics-players' => 'Spelarar', + 'podcast-analytics-listening-time' => 'Lyttetid', + 'podcast-analytics-time-periods' => 'Tidsperiodar', + 'monetization' => 'Kommersialisering', + 'subscription-list' => 'Alle abonnement', + 'subscription-create' => 'Legg til abonnement', + 'contributors' => 'Bidragsytarar', + 'contributor-list' => 'Alle bidragsytarane', + 'contributor-add' => 'Legg til bidragsytar', + 'broadcast' => 'Kringkast', + 'platforms-podcasting' => 'Podkastingsappar', + 'platforms-social' => 'Sosiale nettverk', + 'platforms-funding' => 'Donasjonslenker', + 'podcast-monetization-other' => 'Anna', +]; diff --git a/modules/Admin/Language/nn-no/Settings.php b/modules/Admin/Language/nn-no/Settings.php new file mode 100644 index 00000000..d05ccfc9 --- /dev/null +++ b/modules/Admin/Language/nn-no/Settings.php @@ -0,0 +1,58 @@ + 'Generelle innstillingar', + 'instance' => [ + 'title' => 'Nettstad', + 'site_icon' => 'Sideikon', + 'site_icon_delete' => 'Slett sideikonet', + 'site_icon_hint' => 'Nettstadikon er det du ser i fanene på nettlesaren, bokmerkelina og når du legg til ein nettstad som snarveg på mobile einingar.', + 'site_icon_helper' => 'Ikonet må vera kvadratisk og minst 512pkt breitt og høgt.', + 'site_name' => 'Nettstadnamn', + 'site_description' => 'Skildring av nettstaden', + 'submit' => 'Lagre', + 'editSuccess' => 'Nettstaden er oppdatert!', + 'deleteIconSuccess' => 'Nettstadikonet er fjerna!', + ], + 'images' => [ + 'title' => 'Bilete', + 'subtitle' => 'Her kan du regenerera alle bileta, basert på dei opplasta originalane. Dette gjer du dersom du ser at det manglar bilete. Dette kan ta ei stund.', + 'regenerate' => 'Regenerer bilete', + 'regenerationSuccess' => 'Alle bileta er regenererte!', + ], + 'housekeeping' => [ + 'title' => 'Reinhald', + 'subtitle' => 'Gjer ulike reinhaldsoppgåver. Bruk dette viss du kjem borti feil med mediafiler eller dataintegritet. Dette kan ta ei stund.', + 'reset_counts' => 'Nullstill teljarar', + 'reset_counts_helper' => 'Dette nullstiller alle datateljarar (tal på fylgjarar, innlegg, kommentarar…).', + 'rewrite_media' => 'Overskriv metadata for medium', + 'rewrite_media_helper' => 'Dette vil sletta alle overflødige mediafiler og laga dei på nytt (bilete, lydfiler, transkriberingar, kapittel, …)', + 'rename_episodes_files' => 'Gje episode-lydfilene nytt namn', + 'rename_episodes_files_hint' => 'Dette alternativet gjev alle episode-lydfilene tilfeldige nye namn. Bruk dette viss lenka til dei private episodane vart leken, for då blir ho i praksis gøymt att.', + 'clear_cache' => 'Slett bufferinnhald', + 'clear_cache_helper' => 'Dette tømmer redis-mellomlageret eller skrivbare/mellomlagra filer.', + 'run' => 'Gjer reinhald', + 'runSuccess' => 'Reinhaldet er utført!', + ], + 'theme' => [ + 'title' => 'Bunad', + 'accent_section_title' => 'Framheva farge', + 'accent_section_subtitle' => 'Vel kva farge som blir framheva på alle dei offentlege sidene.', + 'pine' => 'Furu', + 'crimson' => 'Karmosinraud', + 'amber' => 'Rav', + 'lake' => 'Innsjø', + 'jacaranda' => 'Syrinblå', + 'onyx' => 'Onyks', + 'submit' => 'Lagre', + 'setInstanceThemeSuccess' => 'Bunaden er oppdatert!', + ], +]; diff --git a/modules/Admin/Language/nn-no/Soundbite.php b/modules/Admin/Language/nn-no/Soundbite.php new file mode 100644 index 00000000..65e06cab --- /dev/null +++ b/modules/Admin/Language/nn-no/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Lydbetar', + 'soundbite' => 'Lydbete', + ], + 'messages' => [ + 'createSuccess' => 'Lydbeten er oppretta!', + 'deleteSuccess' => 'Lydbeten er fjerna!', + ], + 'form' => [ + 'title' => 'Ny lydbete', + 'soundbite_title' => 'Tittel på lydbeten', + 'start_time' => 'Start på', + 'duration' => 'Lengd', + 'submit' => 'Lag lydbete', + ], + 'play' => 'Spel lydbeten', + 'stop' => 'Stopp lydbeten', + 'create' => 'Ny lydbete', + 'delete' => 'Slett lydbeten', +]; diff --git a/modules/Admin/Language/nn-no/Validation.php b/modules/Admin/Language/nn-no/Validation.php new file mode 100644 index 00000000..21a34148 --- /dev/null +++ b/modules/Admin/Language/nn-no/Validation.php @@ -0,0 +1,17 @@ + + '{field} er anten ikkje eit bilete, eller er ikkje breitt og høgt nok.', + 'is_image_ratio' => + '{field} er anten ikkje eit bilete, eller har feil forhold mellom høgd og breidd.', + 'is_json' => '{field} inneheld ugyldig JSON.', +]; diff --git a/modules/Admin/Language/nn-no/VideoClip.php b/modules/Admin/Language/nn-no/VideoClip.php new file mode 100644 index 00000000..64e1698d --- /dev/null +++ b/modules/Admin/Language/nn-no/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Videoklypp', + 'status' => [ + 'label' => 'Status', + 'queued' => 'i kø', + 'queued_hint' => 'Klyppet ventar på handsaming.', + 'pending' => 'ventar', + 'pending_hint' => 'Klyppet blir generert snart.', + 'running' => 'køyrer', + 'running_hint' => 'Klyppet blir generert.', + 'failed' => 'mislukka', + 'failed_hint' => 'Greidde ikkje laga klyppet: skriptfeil.', + 'passed' => 'utført', + 'passed_hint' => 'Klyppet vart laga!', + ], + 'clip' => 'Klypp', + 'duration' => 'Jobbtid', + ], + 'title' => 'Filmklypp: {videoClipLabel}', + 'download_clip' => 'Last ned klyppet', + 'create' => 'Nytt filmklypp', + 'go_to_page' => 'Gå til filmklyppsida', + 'retry' => 'Prøv å laga klyppet på nytt', + 'delete' => 'Slett klyppet', + 'logs' => 'Arbeidsloggar', + 'messages' => [ + 'alreadyExistingError' => 'Filmen du prøver å laga finst frå før!', + 'addToQueueSuccess' => 'Filmklyppet er lagt i kø og ventar på å bli laga!', + 'deleteSuccess' => 'Filmklyppet er fjerna!', + ], + 'format' => [ + 'landscape' => 'Liggjande', + 'portrait' => 'Ståande', + 'squared' => 'Kvadratisk', + ], + 'form' => [ + 'title' => 'Nytt filmklypp', + 'params_section_title' => 'Innstillingar for filmklypp', + 'clip_title' => 'Namn på filmklyppet', + 'format' => [ + 'label' => 'Vel format', + 'landscape_hint' => 'Filmar i liggjande 16:9-format er fine til Peertube, Youtube og Vimeo.', + 'portrait_hint' => 'Filmar i ståande 9:16-format er fine til Tiktok, korte Youtube-filmar og Instagram-historier.', + 'squared_hint' => 'Filmar i kvadratisk 1:1-format er fine til Mastodon, Facebook, Twitter og Linkedin.', + ], + 'theme' => 'Vel bunad', + 'start_time' => 'Start på', + 'duration' => 'Lengd', + 'trim_start' => 'Skjer til starten', + 'trim_end' => 'Skjer til slutten', + 'submit' => 'Lag videoklypp', + ], + 'requirements' => [ + 'title' => 'Manglande krav', + 'missing' => 'Du har manglande krav. Pass på å leggja til alle dei påkravde elementa for å laga ein film til denne episoden!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype-bibliotek for GD', + 'transcript' => 'Transkriberingsfil (.srt)', + ], +]; diff --git a/modules/Admin/Language/oc/AboutCastopod.php b/modules/Admin/Language/oc/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/oc/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/oc/Breadcrumb.php b/modules/Admin/Language/oc/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/oc/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/oc/Charts.php b/modules/Admin/Language/oc/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/oc/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/oc/Common.php b/modules/Admin/Language/oc/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/oc/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/oc/Countries.php b/modules/Admin/Language/oc/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/oc/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/oc/Dashboard.php b/modules/Admin/Language/oc/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/oc/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/oc/Episode.php b/modules/Admin/Language/oc/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/oc/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/oc/EpisodeNavigation.php b/modules/Admin/Language/oc/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/oc/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/oc/Fediverse.php b/modules/Admin/Language/oc/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/oc/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/oc/Home.php b/modules/Admin/Language/oc/Home.php new file mode 100644 index 00000000..2f0f3570 --- /dev/null +++ b/modules/Admin/Language/oc/Home.php @@ -0,0 +1,14 @@ + 'Totes los podcasts', + 'no_podcast' => 'Cap de podcast pas trobat', +]; diff --git a/modules/Admin/Language/oc/Install.php b/modules/Admin/Language/oc/Install.php new file mode 100644 index 00000000..5a90a8ce --- /dev/null +++ b/modules/Admin/Language/oc/Install.php @@ -0,0 +1,61 @@ + 'Configuracion manuala', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'Fichièr', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Seguent', + 'submit' => 'Acabar l’installacion', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/oc/Navigation.php b/modules/Admin/Language/oc/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/oc/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/oc/Notifications.php b/modules/Admin/Language/oc/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/oc/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/oc/Page.php b/modules/Admin/Language/oc/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/oc/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/oc/Pager.php b/modules/Admin/Language/oc/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/oc/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/oc/Person.php b/modules/Admin/Language/oc/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/oc/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/oc/Platforms.php b/modules/Admin/Language/oc/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/oc/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/oc/Podcast.php b/modules/Admin/Language/oc/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/oc/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/oc/PodcastNavigation.php b/modules/Admin/Language/oc/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/oc/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/oc/Settings.php b/modules/Admin/Language/oc/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/oc/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/oc/Soundbite.php b/modules/Admin/Language/oc/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/oc/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/oc/Validation.php b/modules/Admin/Language/oc/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/oc/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/oc/VideoClip.php b/modules/Admin/Language/oc/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/oc/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/pl/AboutCastopod.php b/modules/Admin/Language/pl/AboutCastopod.php new file mode 100644 index 00000000..2a65d0d6 --- /dev/null +++ b/modules/Admin/Language/pl/AboutCastopod.php @@ -0,0 +1,22 @@ + 'O Castopod', + 'host_name' => 'Nazwa hosta', + 'version' => 'Wersja Castopod', + 'php_version' => 'Wersja PHP', + 'os' => 'System operacyjny', + 'languages' => 'Języki', + 'update_database' => 'Aktualizuj bazę danych', + 'messages' => [ + 'databaseUpdateSuccess' => 'Baza danych jest aktualna!', + ], +]; diff --git a/modules/Admin/Language/pl/Breadcrumb.php b/modules/Admin/Language/pl/Breadcrumb.php new file mode 100644 index 00000000..34ba50a6 --- /dev/null +++ b/modules/Admin/Language/pl/Breadcrumb.php @@ -0,0 +1,57 @@ + 'okruszki', + config('Admin') + ->gateway => 'Początek', + 'podcasts' => 'podcasty', + 'episodes' => 'odcinki', + 'subscriptions' => 'subskrypcja', + 'contributors' => 'kontrybutorzy', + 'pages' => 'strony', + 'settings' => 'ustawienia', + 'theme' => 'motyw', + 'about' => 'informacje', + 'add' => 'dodaj', + 'new' => 'nowy', + 'edit' => 'edytuj', + 'persons' => 'osoby', + 'publish' => 'publikuj', + 'publish-edit' => 'edytuj publikację', + 'publish-date-edit' => 'edytuj datę publikacji', + 'unpublish' => 'cofnij publikację', + 'delete' => 'usuń', + 'remove' => 'usuń', + 'fediverse' => 'fediwersum', + 'blocked-actors' => 'zablokowani aktorzy', + 'blocked-domains' => 'zablokowane domeny', + 'users' => 'użytkownicy', + 'my-account' => 'moje konto', + 'change-password' => 'zmień hasło', + 'imports' => 'importy', + 'sync-feeds' => 'synchronizuj kanały', + 'platforms' => 'platformy', + 'social' => 'sieci społecznościowe', + 'funding' => 'finansowanie', + 'monetization-other' => 'inna monetyzacja', + 'analytics' => 'analityka', + 'locations' => 'lokalizacje', + 'webpages' => 'strony internetowe', + 'unique-listeners' => 'unikalni słuchacze', + 'players' => 'odtwarzacze', + 'listening-time' => 'czas odsłuchu', + 'time-periods' => 'przedziały czasu', + 'soundbites' => 'zajawki', + 'video-clips' => 'klipy wideo', + 'embed' => 'odtwarzacz do osadzenia', + 'notifications' => 'powiadomienia', + 'suspend' => 'wstrzymaj', +]; diff --git a/modules/Admin/Language/pl/Charts.php b/modules/Admin/Language/pl/Charts.php new file mode 100644 index 00000000..ebd13d1d --- /dev/null +++ b/modules/Admin/Language/pl/Charts.php @@ -0,0 +1,41 @@ + 'Pobrania odcinków według usługi (dla minionego tygodnia)', + 'by_player_weekly' => 'Pobrania odcinków według odtwarzacza (dla minionego tygodnia)', + 'by_player_yearly' => 'Pobrania odcinków według odtwarzacza (dla minionego roku)', + 'by_device_weekly' => 'Pobrania odcinków według urządzenia (dla minionego tygodnia)', + 'by_os_weekly' => 'Pobrania odcinków według systemu operacyjnego (dla minionego tygodnia)', + 'podcast_by_region' => 'Pobrania odcinków według regionu (dla minionego tygodnia)', + 'unique_daily_listeners' => 'Unikalni słuchacze dziennie', + 'unique_monthly_listeners' => 'Unikalni słuchacze miesięcznie', + 'by_browser' => 'Wykorzystanie stron internetowych według przeglądarki (dla minionego tygodnia)', + 'podcast_by_day' => 'Dzienne pobrania odcinków', + 'podcast_by_month' => 'Miesięczne pobrania odcinków', + 'episode_by_day' => 'Dzienne pobrania odcinków (pierwsze 60 dni)', + 'episode_by_month' => 'Miesięczne pobrania odcinków', + 'episodes_by_day' => + '5 najnowszych pobrań odcinków (w ciągu ich pierwszych 60 dni)', + 'by_country_weekly' => 'Pobrania odcinków według kraju (dla minionego tygodnia)', + 'by_country_yearly' => 'Pobrania odcinków według urządzenia (dla minionego roku)', + 'by_domain_weekly' => 'Odwiedziny stron internetowych według źródła (dla minionego tygodnia)', + 'by_domain_yearly' => 'Odwiedziny stron internetowych według źródła (dla minionego roku)', + 'by_entry_page' => 'Odwiedziny stron internetowych według landing page (dla minionego tygodnia)', + 'podcast_bots' => 'Boty (pająki)', + 'daily_listening_time' => 'Dzienny łączny czas słuchania', + 'monthly_listening_time' => 'Miesięczny łączny czas słuchania', + 'by_weekday' => 'Według dnia tygodnia (dla minionych 60 dni)', + 'by_hour' => 'Według pory dnia (dla minionych 60 dni)', + 'podcast_by_bandwidth' => 'Dzienna przepustowość (w MB)', + 'total_storage_by_month' => 'Miesięczne przechowywanie (w MB)', + 'total_bandwidth_by_month' => 'Miesięczne zużycie transferu (w MB)', + 'total_bandwidth_by_month_limit' => 'Ograniczono do {totalBandwidth} miesięcznie', +]; diff --git a/modules/Admin/Language/pl/Common.php b/modules/Admin/Language/pl/Common.php new file mode 100644 index 00000000..5d3fba6b --- /dev/null +++ b/modules/Admin/Language/pl/Common.php @@ -0,0 +1,52 @@ + 'Tak', + 'no' => 'Nie', + 'cancel' => 'Anuluj', + 'optional' => 'Opcjonalne', + 'more' => 'Więcej', + 'no_data' => 'Nie znaleziono danych!', + 'close' => 'Zamknij', + 'edit' => 'Edytuj', + 'copy' => 'Kopiuj', + 'copied' => 'Skopiowano!', + 'home' => 'Początek', + 'explicit' => 'Dla dorosłych', + 'powered_by' => 'Wspierane przez {castopod}', + 'actions' => 'Akcje', + 'pageInfo' => 'Strona {currentPage} z {pageCount}', + 'go_back' => 'Wróć', + 'forms' => [ + 'editor' => [ + 'write' => 'Napisz', + 'preview' => 'Podgląd', + 'help' => 'Obsługiwane przez markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Naciśnij, aby zaznaczyć', + 'loadingText' => 'Wczytywanie…', + 'noResultsText' => 'Nie znaleziono wyników', + 'noChoicesText' => 'Brak możliwości wyboru', + 'maxItemText' => 'Nie można dodać więcej elementów', + ], + 'upload_file' => 'Prześlij plik', + 'remote_url' => 'Zdalny URL', + 'save' => 'Zapisz', + ], + 'play_episode_button' => [ + 'play' => 'Odtwarzaj', + 'playing' => 'Odtwarzanie', + ], + 'size_limit' => 'Limit rozmiaru: {0}.', + 'choose_interact' => 'Wybierz sposób interakcji', + 'view' => 'Podgląd', +]; diff --git a/modules/Admin/Language/pl/Countries.php b/modules/Admin/Language/pl/Countries.php new file mode 100644 index 00000000..53f104a8 --- /dev/null +++ b/modules/Admin/Language/pl/Countries.php @@ -0,0 +1,264 @@ + 'Andora', + 'AE' => 'Zjednoczone Emiraty Arabskie', + 'AF' => 'Afganistan', + 'AG' => 'Antigua i Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarktyka', + 'AR' => 'Argentyna', + 'AS' => 'Samoa Amerykańskie', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Wyspy Alandzkie', + 'AZ' => 'Azerbejdżan', + 'BA' => 'Bośnia i Hercegowina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesz', + 'BE' => 'Belgia', + 'BF' => 'Burkina Faso', + 'BG' => 'Bułgaria', + 'BH' => 'Bahrajn', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint-Barthélemy', + 'BM' => 'Bermudy', + 'BN' => 'Brunei', + 'BO' => 'Boliwia', + 'BQ' => 'Bonaire, Sint Eustatius i Saba', + 'BR' => 'Brazylia', + 'BS' => 'Bahamy', + 'BT' => 'Bhutan', + 'BV' => 'Wyspa Bouveta', + 'BW' => 'Botswana', + 'BY' => 'Białoruś', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Wyspy Kokosowe', + 'CD' => 'Demokratyczna Republika Konga', + 'CF' => 'Republika Środkowoafrykańska', + 'CG' => 'Kongo', + 'CH' => 'Szwajcaria', + 'CI' => "Wybrzeże Kości Słoniowej", + 'CK' => 'Wyspy Cooka', + 'CL' => 'Chile', + 'CM' => 'Kamerun', + 'CN' => 'Chiny', + 'CO' => 'Kolumbia', + 'CR' => 'Kostaryka', + 'CU' => 'Kuba', + 'CV' => 'Republika Zielonego Przylądka', + 'CW' => 'Curacao', + 'CX' => 'Wyspa Bożego Narodzenia', + 'CY' => 'Cypr', + 'CZ' => 'Czechy', + 'DE' => 'Niemcy', + 'DJ' => 'Dżibuti', + 'DK' => 'Dania', + 'DM' => 'Dominika', + 'DO' => 'Dominikana', + 'DZ' => 'Algieria', + 'EC' => 'Ekwador', + 'EE' => 'Estonia', + 'EG' => 'Egipt', + 'EH' => 'Sahara Zachodnia', + 'ER' => 'Erytrea', + 'ES' => 'Hiszpania', + 'ET' => 'Etiopia', + 'FI' => 'Finlandia', + 'FJ' => 'Fidżi', + 'FK' => 'Falklandy', + 'FM' => 'Mikronezja', + 'FO' => 'Wyspy Owcze', + 'FR' => 'Francja', + 'GA' => 'Gabon', + 'GB' => 'Wielka Brytania', + 'GD' => 'Grenada', + 'GE' => 'Gruzja', + 'GF' => 'Gujana Francuska', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Grenlandia', + 'GM' => 'Gambia', + 'GN' => 'Gwinea', + 'GP' => 'Gwadelupa', + 'GQ' => 'Gwinea Równikowa', + 'GR' => 'Grecja', + 'GS' => 'Georgia Południowa i Sandwich Południowy', + 'GT' => 'Gwatemala', + 'GU' => 'Guam', + 'GW' => 'Gwinea Bissau', + 'GY' => 'Gujana', + 'HK' => 'Hongkong', + 'HM' => 'Wyspy Heard i McDonalda', + 'HN' => 'Honduras', + 'HR' => 'Chorwacja', + 'HT' => 'Haiti', + 'HU' => 'Węgry', + 'ID' => 'Indonezja', + 'IE' => 'Irlandia', + 'IL' => 'Izrael', + 'IM' => 'Wyspa Man', + 'IN' => 'Indie', + 'IO' => 'Brytyjskie Terytorium Oceanu Indyjskiego', + 'IQ' => 'Irak', + 'IR' => 'Iran', + 'IS' => 'Islandia', + 'IT' => 'Włochy', + 'JE' => 'Wyspa Jersey', + 'JM' => 'Jamajka', + 'JO' => 'Jordania', + 'JP' => 'Japonia', + 'KE' => 'Kenia', + 'KG' => 'Kirgistan', + 'KH' => 'Kambodża', + 'KI' => 'Kiribati', + 'KM' => 'Komory', + 'KN' => 'Saint Kitts i Nevis', + 'KP' => "Korea Północna", + 'KR' => 'Korea Południowa', + 'KW' => 'Kuwejt', + 'KY' => 'Kajmany', + 'KZ' => 'Kazachstan', + 'LA' => "Laos", + 'LB' => 'Liban', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Litwa', + 'LU' => 'Luksemburg', + 'LV' => 'Łotwa', + 'LY' => 'Libia', + 'MA' => 'Maroko', + 'MC' => 'Monako', + 'MD' => 'Mołdawia', + 'ME' => 'Czarnogóra', + 'MF' => 'Saint-Martin (Francja)', + 'MG' => 'Madagaskar', + 'MH' => 'Wyspy Marshalla', + 'MK' => 'Macedonia Północna', + 'ML' => 'Mali', + 'MM' => 'Mjanma', + 'MN' => 'Mongolia', + 'MO' => 'Makau', + 'MP' => 'Mariany Północne', + 'MQ' => 'Martynika', + 'MR' => 'Mauretania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Malediwy', + 'MW' => 'Malawi', + 'MX' => 'Meksyk', + 'MY' => 'Malezja', + 'MZ' => 'Mozambik', + 'N/A' => 'Nie dotyczy (lokalny IP…)', + 'NA' => 'Namibia', + 'NC' => 'Nowa Kaledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk', + 'NG' => 'Nigeria', + 'NI' => 'Nikaragua', + 'NL' => 'Holandia', + 'NO' => 'Norwegia', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nowa Zelandia', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Polinezja Francuska', + 'PG' => 'Papua-Nowa Gwinea', + 'PH' => 'Filipiny', + 'PK' => 'Pakistan', + 'PL' => 'Polska', + 'PM' => 'Saint-Pierre i Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Portoryko', + 'PS' => 'Palestyna', + 'PT' => 'Portugalia', + 'PW' => 'Palau', + 'PY' => 'Paragwaj', + 'QA' => 'Katar', + 'RE' => 'Reunion', + 'RO' => 'Rumunia', + 'RS' => 'Serbia', + 'RU' => 'Rosja', + 'RW' => 'Rwanda', + 'SA' => 'Arabia Saudyjska', + 'SB' => 'Wyspy Salomona', + 'SC' => 'Seszele', + 'SD' => 'Sudan', + 'SE' => 'Szwecja', + 'SG' => 'Singapur', + 'SH' => 'Wyspa Świętej Heleny, Wyspa Wniebowstąpienia i Tristan da Cunha', + 'SI' => 'Słowenia', + 'SJ' => 'Svalbard i Jan Mayen', + 'SK' => 'Słowacja', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Surinam', + 'SS' => 'Sudan Południowy', + 'ST' => 'Wyspy Świętego Tomasza i Książęca', + 'SV' => 'Salwador', + 'SX' => 'Sint Maarten', + 'SY' => 'Syria', + 'SZ' => 'Suazi', + 'TC' => 'Turks i Caicos', + 'TD' => 'Czad', + 'TF' => 'Francuskie Terytoria Południowe i Antarktyczne', + 'TG' => 'Togo', + 'TH' => 'Tajlandia', + 'TJ' => 'Tadżykistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor Wschodni', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunezja', + 'TO' => 'Tonga', + 'TR' => 'Turcja', + 'TT' => 'Trynidad i Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Tajwan', + 'TZ' => 'Tanzania', + 'UA' => 'Ukraina', + 'UG' => 'Uganda', + 'UM' => 'Dalekie Wyspy Mniejsze Stanów Zjednoczonych', + 'US' => 'Stany Zjednoczone', + 'UY' => 'Urugwaj', + 'UZ' => 'Uzbekistan', + 'VA' => 'Watykan', + 'VC' => 'Saint Vincent i Grenadyny', + 'VE' => 'Wenezuela', + 'VG' => 'Brytyjskie Wyspy Dziewicze', + 'VI' => 'Wyspy Dziewicze Stanów Zjednoczonych', + 'VN' => 'Wietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis i Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Majotta', + 'ZA' => 'Południowa Afryka', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/pl/Dashboard.php b/modules/Admin/Language/pl/Dashboard.php new file mode 100644 index 00000000..26030e1f --- /dev/null +++ b/modules/Admin/Language/pl/Dashboard.php @@ -0,0 +1,28 @@ + 'Panel administratora', + 'welcome_message' => 'Witamy w panelu administracyjnym!', + 'podcasts' => [ + 'title' => 'Podcasty', + 'not_found' => 'Brak opublikowanych podcastów', + 'last_published' => 'Ostatnio opublikowane {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Odcinki', + 'not_found' => 'Brak opublikowanych odcinków', + 'last_published' => 'Ostatnio opublikowane {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Pamięć', + 'subtitle' => '{totalUploaded} z {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/pl/Episode.php b/modules/Admin/Language/pl/Episode.php new file mode 100644 index 00000000..5c84ab2b --- /dev/null +++ b/modules/Admin/Language/pl/Episode.php @@ -0,0 +1,227 @@ + 'Sezon {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Odcinek {episodeNumber}', + 'number_abbr' => 'Odc. {episodeNumber}', + 'season_episode' => 'Sezon {seasonNumber} odcinek {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}O{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# komentarz} + few {# komentarze} + other {# komentarzy} + }', + 'all_podcast_episodes' => 'Wszystkie odcinki podcastu', + 'back_to_podcast' => 'Wróć do podcastu', + 'edit' => 'Edytuj', + 'preview' => 'Podgląd', + 'publish' => 'Publikuj', + 'publish_edit' => 'Edytuj publikację', + 'publish_date_edit' => 'Edytuj datę publikacji', + 'unpublish' => 'Cofnij publikację', + 'publish_error' => 'Odcinek jest już opublikowany.', + 'publish_edit_error' => 'Odcinek jest już opublikowany.', + 'publish_cancel_error' => 'Odcinek jest już opublikowany.', + 'publish_date_edit_error' => 'Odcinek nie został jeszcze opublikowany, nie możesz edytować daty jego publikacji.', + 'publish_date_edit_future_error' => 'Data publikacji odcinka może być ustawiona tylko na przeszłą datę! Jeśli chcesz ją ponownie zaplanować, należy najpierw cofnąć publikację.', + 'publish_date_edit_success' => 'Data publikacji odcinka została pomyślnie zaktualizowana!', + 'unpublish_error' => 'Odcinek nie jest opublikowany.', + 'delete' => 'Usuń', + 'go_to_page' => 'Przejdź do strony', + 'create' => 'Dodaj odcinek', + 'publication_status' => [ + 'published' => 'Opublikowany', + 'with_podcast' => 'Opublikowano', + 'scheduled' => 'Zaplanowany', + 'not_published' => 'Nieopublikowany', + ], + 'with_podcast_hint' => 'Opublikowany w tym samym czasie co podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Szukaj odcinka', + 'clear' => 'Wyczyść wyszukiwanie', + 'submit' => 'Szukaj', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# osoba} + few {# osoby} + other {# osób} + }', + 'episode' => 'Odcinek', + 'visibility' => 'Widoczność', + 'downloads' => 'Pobrane', + 'comments' => 'Komentarze', + 'actions' => 'Działania', + ], + 'messages' => [ + 'createSuccess' => 'Odcinek został pomyślnie utworzony!', + 'editSuccess' => 'Odcinek został pomyślnie zaktualizowany!', + 'publishSuccess' => '{publication_status, select, + published {Odcinek został pomyślnie opublikowany!} + scheduled {Publikacja odcinka pomyślnie zaplanowana!} + with_podcast {Ten odcinek zostanie opublikowany w tym samym czasie co podcast.} + other {Ten odcinek nie jest opublikowany.} + }', + 'publishCancelSuccess' => 'Publikacja odcinka pomyślnie anulowana!', + 'unpublishBeforeDeleteTip' => 'Musisz cofnąć publikację odcinka przed jego usunięciem.', + 'scheduleDateError' => 'Zaplanowana data musi być ustawiona!', + 'deletePublishedEpisodeError' => 'Musisz cofnąć publikację odcinka przed jego usunięciem.', + 'deleteSuccess' => 'Odcinek pomyślnie usunięty!', + 'deleteError' => 'Nie udało się usunąć {type, select, + transcript {transkrypcji} + chapters {rozdziału} + image {okładki} + audio {audio} + other {mediów} + } odcinka.', + 'deleteFileError' => 'Nie można było skasować pliku {type, select, + transcript {transkryptu} + chapters {rozdziałów} + image {okładki} + audio {audio} + other {medium} + } {file_key}. Możesz chcieć zrobić to ręcznie.', + 'sameSlugError' => 'Odcinek z wybranym slugiem już istnieje.', + ], + 'form' => [ + 'file_size_error' => + 'Rozmiar Twojego pliku jest za duży! Maksymalny rozmiar to {0}. Zwiększ wartości `memory_limit`, `upload_max_filesize` i `post_max_size` w pliku konfiguracyjnym php, a następnie uruchom ponownie serwer www, aby przesłać plik.', + 'audio_file' => 'Plik audio', + 'audio_file_hint' => 'Wybierz plik audio w formacie .mp3 lub .m4a.', + 'info_section_title' => 'Informacje o odcinku', + 'cover' => 'Okładka odcinka', + 'cover_hint' => + 'Jeśli nie ustawisz okładki, zamiast niej zostanie użyta okładka podcastu.', + 'cover_size_hint' => 'Okładka musi być kwadratowa o szerokości i wysokości co najmniej 1400 pikseli.', + 'title' => 'Tytuł', + 'title_hint' => + 'Powinien zawierać jasną i zwięzłą nazwę odcinka. Nie podawaj tutaj numerów odcinków ani sezonów.', + 'permalink' => 'Odnośnik bezpośredni', + 'season_number' => 'Sezon', + 'episode_number' => 'Odcinek', + 'type' => [ + 'label' => 'Typ', + 'full' => 'Pełny', + 'full_hint' => 'Pełna zawartość (odcinek)', + 'trailer' => 'Zwiastun', + 'trailer_hint' => 'Krótka, promocyjna treść przedstawiająca bieżący program', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Dodatkowa treść do programu (np. informacje zza kulis lub wywiady z obsadą) albo treści promujące inne programy', + ], + 'premium_title' => 'Premium', + 'premium' => 'Odcinek dostępny wyłącznie dla subskrybentów premium', + 'parental_advisory' => [ + 'label' => 'Kontrola rodzicielska', + 'hint' => 'Czy odcinek zawiera treści dla dorosłych?', + 'undefined' => 'niezdefiniowano', + 'clean' => 'Czysta', + 'explicit' => 'Dla dorosłych', + ], + 'show_notes_section_title' => 'Notatki programu', + 'show_notes_section_subtitle' => + 'Do 4000 znaków, pisz krótko i zwięźle. Notatki programu pomagają potencjalnym słuchaczom w znalezieniu odcinka.', + 'description' => 'Opis', + 'description_footer' => 'Stopka opisu', + 'description_footer_hint' => + 'Ten tekst jest dodawany na końcu każdego opisu odcinka; jest to dobre miejsce do wpisania np. linków społecznościowych.', + 'additional_files_section_title' => 'Dodatkowe pliki', + 'additional_files_section_subtitle' => + 'Pliki te mogą być używane przez inne platformy, aby zapewnić lepsze wrażenia odbiorcom. Więcej informacji znajdziesz w {podcastNamespaceLink}.', + 'location_section_title' => 'Lokalizacja', + 'location_section_subtitle' => 'O jakim miejscu jest ten odcinek?', + 'location_name' => 'Nazwa lub adres lokalizacji', + 'location_name_hint' => 'Może to być prawdziwa lub fikcyjna lokalizacja', + 'transcript' => 'Transkrypcja (napisy / podpisy kodowane)', + 'transcript_hint' => 'Wspierane są tylko .srt lub .vtt.', + 'transcript_download' => 'Pobierz transkrypcję', + 'transcript_file' => 'Plik transkrypcji (.srt lub .vtt)', + 'transcript_remote_url' => 'Zdalny adres URL dla transkrypcji', + 'transcript_file_delete' => 'Usuń plik transkrypcji', + 'chapters' => 'Rozdziały', + 'chapters_hint' => 'Plik musi być w formacie JSON Chapters.', + 'chapters_download' => 'Pobierz rozdziały', + 'chapters_file' => 'Plik rozdziałów', + 'chapters_remote_url' => 'Zdalny adres URL dla pliku rozdziałów', + 'chapters_file_delete' => 'Usuń plik rozdziałów', + 'advanced_section_title' => 'Parametry Zaawansowane', + 'advanced_section_subtitle' => + 'Jeśli potrzebujesz tagów RSS, których Castopod nie obsługuje, ustaw je tutaj.', + 'custom_rss' => 'Własne tagi RSS dla odcinka', + 'custom_rss_hint' => 'Zostaną wstawione w tagu ❬item❭.', + 'block' => 'Odcinek powinien być ukryty w publicznych katalogach', + 'block_hint' => + 'Pokazywanie lub ukrywanie odcinka: przełączanie tej funkcji zapobiega pojawieniu się odcinka w Apple Podcasts, Google Podcasts, a także aplikacjach innych firm, które pobierają z tych katalogów. (Niegwarantowane)', + 'submit_create' => 'Stwórz odcinek', + 'submit_edit' => 'Zapisz odcinek', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Wróć do panelu odcinka', + 'post' => 'Twój wpis ogłoszeniowy', + 'post_hint' => + "Napisz wiadomość, aby ogłosić publikację swojego odcinka. Wiadomość zostanie wyemitowana do wszystkich Twoich obserwujących w fediwersum i pojawi się na stronie głównej Twojego podcastu.", + 'message_placeholder' => 'Napisz swoją wiadomość…', + 'publication_date' => 'Data publikacji', + 'publication_method' => [ + 'now' => 'Teraz', + 'schedule' => 'Zaplanuj', + 'with_podcast' => 'Opublikuj razem z podcastem', + ], + 'scheduled_publication_date' => 'Planowana data publikacji', + 'scheduled_publication_date_clear' => 'Wyczyść datę publikacji', + 'scheduled_publication_date_hint' => + 'Możesz zaplanować wydanie odcinka, ustawiając przyszłą datę publikacji. To pole musi być sformatowane jako YYYY-MM-DD HH:mm', + 'submit' => 'Opublikuj', + 'submit_edit' => 'Edytuj publikację', + 'cancel_publication' => 'Anuluj publikację', + 'message_warning' => 'Nie napisałeś wiadomości do swojego wpisu ogłoszeniowego!', + 'message_warning_hint' => 'Napisanie wiadomości zwiększa zaangażowanie społeczne, co skutkuje lepszą widocznością Twojego odcinka.', + 'message_warning_submit' => 'Opublikuj mimo to', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nowa data publikacji', + 'new_publication_date_hint' => 'Musi być ustawiona przeszła data.', + 'submit' => 'Edytuj datę publikacji', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Cofnięcie publikacji odcinka spowoduje usunięcie wszystkich powiązanych z nim wpisów i usunięcie go z kanału RSS podcastu.", + 'understand' => 'Rozumiem, chcę cofnąć publikację odcinka', + 'submit' => 'Cofnij publikację', + ], + 'delete_form' => [ + 'disclaimer' => + "Usunięcie odcinka spowoduje usunięcie wszystkich plików multimedialnych, komentarzy, klipów wideo i powiązanych z nimi zajawek.", + 'understand' => 'Rozumiem, chcę usunąć odcinek', + 'submit' => 'Usuń', + ], + 'embed' => [ + 'title' => 'Odtwarzacz osadzalny', + 'label' => + 'Wybierz kolor motywu, skopiuj osadzalny odtwarzacz do schowka, a następnie wklej go na swojej stronie internetowej.', + 'clipboard_iframe' => 'Skopiuj odtwarzacz osadzalny do schowka', + 'clipboard_url' => 'Skopiuj adres do schowka', + 'dark' => 'Ciemny', + 'dark-transparent' => 'Ciemny przezroczysty', + 'light' => 'Jasny', + 'light-transparent' => 'Jasny przezroczysty', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'tryb szkicu', + 'text' => '{publication_status, select, + published {Ten odcinek jeszcze nie został opublikowany.} + scheduled {Ten odcinek zostanie opublikowany {publication_date}.} + with_podcast {Ten odcinek zostanie opublikowany w tym samym momencie, co podcast.} + other {Ten odcinek jeszcze nie został opublikowany.} + }', + 'preview' => 'Podgląd', + ], +]; diff --git a/modules/Admin/Language/pl/EpisodeNavigation.php b/modules/Admin/Language/pl/EpisodeNavigation.php new file mode 100644 index 00000000..48564e3d --- /dev/null +++ b/modules/Admin/Language/pl/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Wyświetl stronę odcinka', + 'dashboard' => 'Panel odcinka', + 'episode-view' => 'Początek', + 'episode-edit' => 'Edytuj odcinek', + 'episode-persons-manage' => 'Zarządzaj osobami', + 'embed-add' => 'Odtwarzacz do osadzania', + 'clips' => 'Klipy', + 'video-clips-list' => 'Klipy wideo', + 'video-clips-create' => 'Nowy klip wideo', + 'soundbites-list' => 'Zajawki', + 'soundbites-create' => 'Nowa zajawka', +]; diff --git a/modules/Admin/Language/pl/Fediverse.php b/modules/Admin/Language/pl/Fediverse.php new file mode 100644 index 00000000..8c0bda3c --- /dev/null +++ b/modules/Admin/Language/pl/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Nie udało się znaleźć użytkownika!', + 'blockActorSuccess' => '{actor} został zablokowany!', + 'unblockActorSuccess' => 'Aktor został odblokowany!', + 'blockDomainSuccess' => '{domain} została zablokowana!', + 'unblockDomainSuccess' => '{domain} została odblokowana!', + ], + 'blocked_actors' => 'Zablokowane konta', + 'blocked_domains' => 'Zablokowane domeny', + 'block_lists_form' => [ + 'handle' => 'Uchwyt konta', + 'handle_hint' => 'Wpisz @nazwaużytkownika@domena konta.', + 'domain' => 'Nazwa domeny', + 'submit' => 'Zablokuj!', + ], + 'list' => [ + 'actor' => 'Konto', + 'domain' => 'Nazwa domeny', + 'unblock' => 'Odblokuj', + ], +]; diff --git a/modules/Admin/Language/pl/Home.php b/modules/Admin/Language/pl/Home.php new file mode 100644 index 00000000..0fbf6d17 --- /dev/null +++ b/modules/Admin/Language/pl/Home.php @@ -0,0 +1,14 @@ + 'Wszystkie podcasty', + 'no_podcast' => 'Nie znaleziono podcastu', +]; diff --git a/modules/Admin/Language/pl/Install.php b/modules/Admin/Language/pl/Install.php new file mode 100644 index 00000000..28724a3e --- /dev/null +++ b/modules/Admin/Language/pl/Install.php @@ -0,0 +1,61 @@ + 'Konfiguracja ręczna', + 'manual_config_subtitle' => + 'Stwórz plik `.env` ze swoimi ustawieniami i odśwież stronę, aby kontynuować instalację.', + 'form' => [ + 'instance_config' => 'Konfiguracja instancji', + 'hostname' => 'Nazwa hosta', + 'media_base_url' => 'Bazowy URL mediów', + 'media_base_url_hint' => + 'Jeśli korzystasz z CDNa i/lub zewnętrznej usługi analitycznej, możesz ustawić je tutaj.', + 'admin_gateway' => 'Strona administracyjna', + 'admin_gateway_hint' => + 'Droga dostępu do obszaru administracyjnego (np. https://example.com/cp-admin). Domyślnie jest ustawiona jako cp-admin, ale ze względów bezpieczeństwa zalecamy zmianę tej nazwy.', + 'auth_gateway' => 'Strona uwierzytelniania', + 'auth_gateway_hint' => + 'Dostęp do stron uwierzytelniających (np. https://example.com/cp-auth). Domyślnie jest ustawiony jako cp-auth, ale ze względów bezpieczeństwa zalecamy zmianę tej nazwy.', + 'database_config' => 'Konfiguracja bazy danych', + 'database_config_hint' => + 'Castopod musi połączyć się z bazą danych MySQL (lub MariaDB). Jeśli nie masz tych wymaganych informacji, skontaktuj się z administratorem serwera.', + 'db_hostname' => 'Nazwa hosta bazy danych', + 'db_name' => 'Nazwa bazy danych', + 'db_username' => 'Nazwa użytkownika bazy danych', + 'db_password' => 'Hasło bazy danych', + 'db_prefix' => 'Prefiks bazy danych', + 'db_prefix_hint' => + "Prefiks nazw tabel Castopod — pozostaw bez zmian, jeśli nie wiesz, co to znaczy.", + 'cache_config' => 'Konfiguracja pamięci podręcznej', + 'cache_config_hint' => + 'Wybierz preferowany mechanizm pamięci podręcznej. Zostaw domyślną wartość, jeśli nie masz pojęcia, co to znaczy.', + 'cache_handler' => 'Mechanizm pamięci podręcznej', + 'cacheHandlerOptions' => [ + 'file' => 'Plik', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Dalej', + 'submit' => 'Zakończ instalację', + 'create_superadmin' => 'Utwórz swoje konto superadministratora', + 'email' => 'Email', + 'username' => 'Nazwa użytkownika', + 'password' => 'Hasło', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Twoje konto superadministratora zostało pomyślnie utworzone. Zaloguj się, aby rozpocząć podcastowanie!', + 'databaseConnectError' => + 'Castopod nie mógł połączyć się z Twoją bazą danych. Edytuj konfigurację bazy danych i spróbuj ponownie.', + 'writeError' => + "Nie można utworzyć/zapisać pliku `.env`. Musisz go utworzyć ręcznie, postępując zgodnie z szablonem `.env.example` w pakiecie Castopod.", + ], +]; diff --git a/modules/Admin/Language/pl/Navigation.php b/modules/Admin/Language/pl/Navigation.php new file mode 100644 index 00000000..c7c14989 --- /dev/null +++ b/modules/Admin/Language/pl/Navigation.php @@ -0,0 +1,44 @@ + 'Przełącz pasek boczny', + 'go_to_website' => 'Idź do strony internetowej', + 'go_to_admin' => 'Przejdź do panelu administratora', + 'not-authorized' => 'Brak uprawnień', + 'dashboard' => 'Panel', + 'admin' => 'Strona główna', + 'podcasts' => 'Podcasty', + 'podcast-list' => 'Wszystkie podcasty', + 'podcast-create' => 'Nowy podcast', + 'all-podcast-imports' => 'Wszystkie importy podcastów', + 'podcast-imports-add' => 'Importuj podcast', + 'persons' => 'Osoby', + 'person-list' => 'Wszystkie osoby', + 'person-create' => 'Nowa osoba', + 'fediverse' => 'Fediwersum', + 'fediverse-blocked-actors' => 'Zablokowane konta', + 'fediverse-blocked-domains' => 'Zablokowane domeny', + 'users' => 'Użytkownicy', + 'user-list' => 'Wszyscy użytkownicy', + 'user-create' => 'Nowy użytkownik', + 'pages' => 'Strony', + 'page-list' => 'Wszystkie strony', + 'page-create' => 'Nowa strona', + 'settings' => 'Ustawienia', + 'settings-general' => 'Ogólne', + 'settings-theme' => 'Motyw', + 'admin-about' => 'Informacje', + 'account' => [ + 'my-account' => 'Moje konto', + 'change-password' => 'Zmień hasło', + 'logout' => 'Wyloguj', + ], +]; diff --git a/modules/Admin/Language/pl/Notifications.php b/modules/Admin/Language/pl/Notifications.php new file mode 100644 index 00000000..22d4fd6c --- /dev/null +++ b/modules/Admin/Language/pl/Notifications.php @@ -0,0 +1,19 @@ + 'Powiadomienia', + 'reply' => '{actor_username} odpowiedział na Twój post', + 'favourite' => '{actor_username} polubił Twój post', + 'reblog' => '{actor_username} udostępnił Twój post', + 'follow' => '{actor_username} zaczął Cię obserwować', + 'no_notifications' => 'Brak powiadomień', + 'mark_all_as_read' => 'Oznacz wszystkie jako przeczytane', +]; diff --git a/modules/Admin/Language/pl/Page.php b/modules/Admin/Language/pl/Page.php new file mode 100644 index 00000000..a8d0a93e --- /dev/null +++ b/modules/Admin/Language/pl/Page.php @@ -0,0 +1,30 @@ + 'Wróć do początku', + 'page' => 'Strona', + 'all_pages' => 'Wszystkie strony', + 'create' => 'Nowa strona', + 'go_to_page' => 'Idź do strony', + 'edit' => 'Edytuj stronę', + 'delete' => 'Usuń stronę', + 'form' => [ + 'title' => 'Tytuł', + 'permalink' => 'Link bezpośredni', + 'content' => 'Treść', + 'submit_create' => 'Stwórz stronę', + 'submit_edit' => 'Zapisz', + ], + 'messages' => [ + 'createSuccess' => 'Strona “{pageTitle}” została pomyślnie utworzona!', + 'editSuccess' => 'Strona została pomyślnie uaktualniona!', + ], +]; diff --git a/modules/Admin/Language/pl/Pager.php b/modules/Admin/Language/pl/Pager.php new file mode 100644 index 00000000..ac835244 --- /dev/null +++ b/modules/Admin/Language/pl/Pager.php @@ -0,0 +1,21 @@ + 'Nawigacja po stronie', + 'first' => 'Pierwsza', + 'previous' => 'Poprzednia', + 'next' => 'Następna', + 'last' => 'Ostatnia', + 'older' => 'Starsze', + 'newer' => 'Nowsze', + 'invalidTemplate' => '{0} nie jest prawidłowym szablonem pagera.', + 'invalidPaginationGroup' => '{0} nie jest prawidłową grupą paginacji.', +]; diff --git a/modules/Admin/Language/pl/Person.php b/modules/Admin/Language/pl/Person.php new file mode 100644 index 00000000..0386036c --- /dev/null +++ b/modules/Admin/Language/pl/Person.php @@ -0,0 +1,65 @@ + 'Osoby', + 'all_persons' => 'Wszystkie osoby', + 'no_person' => 'Nikogo nie znaleziono!', + 'create' => 'Stwórz osobę', + 'view' => 'Zobacz osobę', + 'edit' => 'Edytuj osobę', + 'delete' => 'Usuń osobę', + 'messages' => [ + 'createSuccess' => 'Osoba została pomyślnie utworzona!', + 'editSuccess' => 'Osoba została pomyślnie zaktualizowana!', + 'deleteSuccess' => 'Osoba została usunięta!', + ], + 'form' => [ + 'avatar' => 'Awatar', + 'avatar_size_hint' => + 'Awatar musi być kwadratowy o szerokości i wysokości co najmniej 400 pikseli.', + 'full_name' => 'Pełne imię i nazwisko', + 'full_name_hint' => 'To jest pełne imię i nazwisko lub pseudonim osoby.', + 'unique_name' => 'Unikalna nazwa', + 'unique_name_hint' => 'Używana do adresów URL', + 'information_url' => 'Adres URL informacji', + 'information_url_hint' => + 'Adres URL do odpowiedniego zasobu informacji o osobie, takiego jak strona domowa lub profil w zewnętrznej platformie.', + 'submit_create' => 'Stwórz osobę', + 'submit_edit' => 'Zapisz osobę', + ], + 'podcast_form' => [ + 'title' => 'Zarządzaj osobami', + 'add_section_title' => 'Dodaj osoby do tego podcastu', + 'add_section_subtitle' => 'Możesz wybrać kilka osób i ról.', + 'persons' => 'Osoby', + 'persons_hint' => + 'Możesz wybrać jedną lub kilka osób o tych samych rolach. Najpierw musisz stworzyć osoby.', + 'roles' => 'Role', + 'roles_hint' => + 'Możesz wybrać żadną, jedną lub kilka ról dla osoby.', + 'submit_add' => 'Dodaj osobę(y)', + 'remove' => 'Usuń', + ], + 'episode_form' => [ + 'title' => 'Zarządzaj osobami', + 'add_section_title' => 'Dodaj osoby do tego odcinka', + 'add_section_subtitle' => 'Możesz wybrać kilka osób i ról.', + 'persons' => 'Osoby', + 'persons_hint' => + 'Możesz wybrać jedną lub kilka osób o tych samych rolach. Najpierw musisz stworzyć osoby.', + 'roles' => 'Role', + 'roles_hint' => + 'Możesz wybrać żadną, jedną lub kilka ról dla osoby.', + 'submit_add' => 'Dodaj osobę(y)', + 'remove' => 'Usuń', + ], + 'credits' => 'Autorzy', +]; diff --git a/modules/Admin/Language/pl/Platforms.php b/modules/Admin/Language/pl/Platforms.php new file mode 100644 index 00000000..d6a97a84 --- /dev/null +++ b/modules/Admin/Language/pl/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Platformy podcastowe', + 'social' => 'Sieci społecznościowe', + 'funding' => 'Linki do finansowania', + ], + 'website' => 'Strona', + 'home_url' => 'Idź do strony {platformName}', + 'register' => 'Zarejestruj', + 'submit_url' => 'Prześlij swój podcast na {platformName}', + 'your_link' => 'Twój link', + 'your_id' => [ + 'podcasting' => 'Twoje ID', + 'social' => 'Twoje ID', + 'funding' => 'Twoje CTA', + ], + 'your_cta' => 'Twoje Call To Action', + 'visible' => 'Wyświetlać na stronie głównej podcastu?', + 'on_embed' => 'Wyświetlać w osadzalnym odtwarzaczu?', + 'remove' => 'Usuń {platformName}', + 'submit' => 'Zapisz', + 'messages' => [ + 'updateSuccess' => 'Linki do platform zostały pomyślnie zaktualizowane!', + 'removeLinkSuccess' => 'Link do platformy został usunięty.', + 'removeLinkError' => + 'Link do platformy nie mógł zostać usunięty. Spróbuj ponownie.', + ], + 'description' => [ + 'podcasting' => 'ID podcastu na tej platformie', + 'social' => 'ID konta podcastu na tej platformie', + 'funding' => 'Wiadomość z wezwaniem do działania', + ], +]; diff --git a/modules/Admin/Language/pl/Podcast.php b/modules/Admin/Language/pl/Podcast.php new file mode 100644 index 00000000..7d91fe7f --- /dev/null +++ b/modules/Admin/Language/pl/Podcast.php @@ -0,0 +1,333 @@ + 'Wszystkie podcasty', + 'no_podcast' => 'Nie znaleziono podcastu!', + 'create' => 'Stwórz podcast', + 'import' => 'Importuj podcast', + 'all_imports' => 'Importy podcastów', + 'new_episode' => 'Nowy Odcinek', + 'view' => 'Wyświetl podcast', + 'edit' => 'Edytuj podcast', + 'publish' => 'Opublikuj podcast', + 'publish_edit' => 'Edytuj publikację', + 'delete' => 'Usuń podcast', + 'see_episodes' => 'Zobacz odcinki', + 'see_contributors' => 'Zobacz kontrybutorów', + 'monetization_other' => 'Inna monetyzacja', + 'go_to_page' => 'Idź do strony', + 'latest_episodes' => 'Najnowsze odcinki', + 'see_all_episodes' => 'Zobacz wszystkie odcinki', + 'draft' => 'Wersja robocza', + 'messages' => [ + 'createSuccess' => 'Podcast został pomyślnie utworzony!', + 'editSuccess' => 'Podcast został pomyślnie zaktualizowany!', + 'importSuccess' => 'Podcast został pomyślnie zaimportowany!', + 'deleteSuccess' => 'Podcast @{podcast_handle} został pomyślnie usunięty!', + 'deletePodcastMediaError' => 'Nie udało się usunąć {type, select, + cover {okładki} + banner {baneru} + other {mediów} + } podcastu.', + 'deleteEpisodeMediaError' => 'Nie udało się usunąć {episode_slug} {type, select, + transcript {transkrypcji} + chapters {rozdziału} + image {okładki} + audio {audio} + other {mediów} + } odcinka.', + 'deletePodcastMediaFolderError' => 'Nie udało się usunąć folderu z mediami podcastu {folder_path}. Możesz go ręcznie usunąć ze swojego dysku.', + 'podcastFeedUpdateSuccess' => 'Zaktualizowano pomyślnie: {number_of_new_episodes, plural, + one {# odcinek został dodany} + few {# odcinki zostały dodane} + other {# odcinków zostało dodanych} + } do podcastu!', + 'podcastFeedUpToDate' => 'Podcast jest już aktualny.', + 'publishError' => 'Ten podcast jest już opublikowany lub zaplanowany do publikacji.', + 'publishEditError' => 'Ten podcast nie jest zaplanowany do publikacji.', + 'publishCancelSuccess' => 'Publikacja odcinka pomyślnie anulowana!', + 'scheduleDateError' => 'Zaplanowana data musi być ustawiona!', + ], + 'form' => [ + 'identity_section_title' => 'Tożsamość podcastu', + 'identity_section_subtitle' => 'Te pola pozwalają Ci zostać zauważonym.', + 'fediverse_section_title' => 'Tożsamość w Fediwersum', + + 'cover' => 'Okładka podcastu', + 'cover_size_hint' => 'Okładka musi być kwadratowa oraz mieć co najmniej 1400px wysokości i szerokości.', + 'banner' => 'Baner podcastu', + 'banner_size_hint' => 'Banner musi mieć proporcje 3:1 oraz mieć co najmniej 1500px szerokości.', + 'banner_delete' => 'Usuń baner podcastu', + 'title' => 'Tytuł', + 'handle' => 'Uchwyt', + 'handle_hint' => + 'Służy do identyfikacji podcastu. Akceptowane są wielkie i małe litery, cyfry i podkreślenia.', + 'type' => [ + 'label' => 'Typ', + 'episodic' => 'Epizodyczny', + 'episodic_hint' => 'Jeśli odcinki mają być pobierane bez określonej kolejności. Najnowsze odcinki zostaną zaprezentowane jako pierwsze.', + 'serial' => 'Seryjny', + 'serial_hint' => 'Jeśli odcinki są przeznaczone do wykorzystania w kolejności sekwencyjnej. Odcinki będą wyświetlane w kolejności numerycznej.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium reprezentowane przez tag podcast:medium w RSS. Zmiana tego może mieć wpływ na wygląd w odtwarzaczach podcastów.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Opisuje kanał dla podcastu.', + 'music' => 'Muzyka', + 'music_hint' => 'Kanał muzyki zorganizowany w "album" z każdym elementem jako utwór w albumie.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specyficzne typy audio z jednym elementem na kanał lub gdzie każdy element reprezentuje rozdział książki.', + ], + 'description' => 'Opis', + 'classification_section_title' => 'Klasyfikacja', + 'classification_section_subtitle' => + 'Te pola wpłyną na twoją publiczność i konkurencję.', + 'language' => 'Język', + 'category' => 'Kategoria', + 'category_placeholder' => 'Wybierz kategorię…', + 'other_categories' => 'Inne kategorie', + 'parental_advisory' => [ + 'label' => 'Kontrola rodzicielska', + 'hint' => 'Czy zawiera treści dla dorosłych?', + 'undefined' => 'niezdefiniowana', + 'clean' => 'Czysta', + 'explicit' => 'Dla dorosłych', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Kto zarządza podcastem?', + 'owner_name' => 'Nazwa właściciela', + 'owner_name_hint' => + 'Wyłącznie do użytku administracyjnego. Widoczne w publicznym kanale RSS.', + 'owner_email' => 'Email właściciela', + 'owner_email_hint' => + 'Będzie używany przez większość platform do weryfikacji własności podcastu. Widoczne w publicznym kanale RSS.', + 'is_owner_email_removed_from_feed' => 'Usuń email właściciela z publicznego kanału RSS', + 'is_owner_email_removed_from_feed_hint' => 'Może być konieczne tymczasowe odkrycie adresu e-mail, aby katalog mógł zweryfikować właściciela podcastu.', + 'publisher' => 'Wydawca', + 'publisher_hint' => + 'Grupa odpowiedzialna za stworzenie programu. Często odnosi się do firmy macierzystej lub sieci podcastów. To pole jest czasami oznaczone jako "Autor".', + 'copyright' => 'Prawa autorskie', + 'location_section_title' => 'Lokalizacja', + 'location_section_subtitle' => 'O jakim miejscu jest ten podcast?', + 'location_name' => 'Nazwa lub adres lokalizacji', + 'location_name_hint' => 'Może to być prawdziwe lub fikcyjne miejsce', + 'monetization_section_title' => 'Monetyzacja', + 'monetization_section_subtitle' => + 'Zarabiaj dzięki swoim odbiorcom.', + 'premium' => 'Premium', + 'premium_by_default' => 'Odcinki muszą być domyślnie ustawione jako premium', + 'premium_by_default_hint' => 'Odcinki podcastów będą domyślnie oznaczone jako premium. Nadal możesz ustawić niektóre odcinki, zwiastuny lub bonusy jako publiczne.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Odwiedź panel OP3 (link zewnętrzny)', + 'op3_hint' => 'Oceń swoje dane analityczne z OP3, otwartej i zaufanej usługi strony trzeciej. Udostępnij, weryfikuj i porównuj swoje dane analityczne za pomocą ekosystemu otwartego podcastingu.', + 'op3_enable' => 'Włącz usługę analityczną OP3', + 'op3_enable_hint' => 'Ze względów bezpieczeństwa dane analityczne odcinków premium nie będą udostępniane OP3.', + 'payment_pointer' => 'Wskaźnik płatności do zarabiania w sieci', + 'payment_pointer_hint' => + 'To tutaj otrzymasz pieniądze dzięki Monetyzacji Internetowej', + 'advanced_section_title' => 'Parametry Zaawansowane', + 'advanced_section_subtitle' => + 'Jeśli potrzebujesz tagów RSS, których Castopod nie obsługuje, ustaw je tutaj.', + 'custom_rss' => 'Własne tagi RSS dla podcastu', + 'custom_rss_hint' => 'Zostanie wstawione w tagu ❬channel❭.', + 'verify_txt' => 'Weryfikacja własności TXT', + 'verify_txt_hint' => 'Zamiast polegać na e-mailu, niektóre usługi firm trzecich mogą potwierdzić twoje prawa własności podcastu, prosząc Cię o osadzenie tekstu weryfikacyjnego w twoim kanale.', + 'verify_txt_helper' => 'Ten tekst jest wstrzykiwany do znacznika .', + 'new_feed_url' => 'Nowy adres URL kanału', + 'new_feed_url_hint' => 'Użyj tego pola, gdy przenosisz się do innej domeny lub platformy hostingowej podcastu. Domyślnie wartość jest ustawiona na bieżący adres URL RSS, jeśli podcast jest importowany.', + 'old_feed_url' => 'Stary URL kanału', + 'partnership' => 'Partnerstwo', + 'partner_id' => 'ID', + 'partner_link_url' => 'Adres URL linku', + 'partner_image_url' => 'Adres URL obrazu', + 'partner_id_hint' => 'Twój własny ID partnera', + 'partner_link_url_hint' => 'Ogólny adres linku partnera', + 'partner_image_url_hint' => 'Ogólny adres obrazu partnera', + 'block' => 'Odcinek powinien być ukryty w publicznych katalogach', + 'block_hint' => + 'Pokazywanie lub ukrywanie odcinka: przełączanie tej funkcji zapobiega pojawieniu się odcinka w Apple Podcasts, Google Podcasts, a także w aplikacjach innych firm, które pobierają z tych katalogów. (Niegwarantowane)', + 'complete' => 'Podcast nie będzie miał nowych odcinków', + 'lock' => 'Zapobiegaj kopiowaniu podcastu', + 'lock_hint' => + 'Celem jest poinformowanie innych platform podcastów, czy są uprawnione do importowania tego kanału. Wartość tak oznacza, że każda próba zaimportowania tego kanału na nową platformę powinna zostać odrzucona.', + 'submit_create' => 'Stwórz podcast', + 'submit_edit' => 'Zapisz podcast', + ], + 'category_options' => [ + 'uncategorized' => 'bez kategorii', + 'arts' => 'Sztuka', + 'business' => 'Biznes', + 'comedy' => 'Komedia', + 'education' => 'Edukacja', + 'fiction' => 'Fikcja', + 'government' => 'Rząd', + 'health_and_fitness' => 'Zdrowie i Fitness', + 'history' => 'Historia', + 'kids_and_family' => 'Dzieci i Rodzina', + 'leisure' => 'Wypoczynek', + 'music' => 'Muzyka', + 'news' => 'Wiadomości', + 'religion_and_spirituality' => 'Religia i Duchowość', + 'science' => 'Nauka', + 'society_and_culture' => 'Społeczność i Kultura', + 'sports' => 'Sport', + 'technology' => 'Technologia', + 'true_crime' => 'Prawdziwe Zbrodnie', + 'tv_and_film' => 'Telewizja i Film', + 'books' => 'Książki', + 'design' => 'Projektowanie', + 'fashion_and_beauty' => 'Moda i Uroda', + 'food' => 'Żywność', + 'performing_arts' => 'Sztuki Sceniczne', + 'visual_arts' => 'Dzieła Wizualne', + 'careers' => 'Kariera', + 'entrepreneurship' => 'Przedsiębiorczość', + 'investing' => 'Inwestowanie', + 'management' => 'Zarządzanie', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Wywiady Komediowe', + 'improv' => 'Improwizacja', + 'stand_up' => 'Stand-Up', + 'courses' => 'Kursy', + 'how_to' => 'Poradnik', + 'language_learning' => 'Nauka Języków', + 'self_improvement' => 'Samorozwój', + 'comedy_fiction' => 'Fikcja komediowa', + 'drama' => 'Dramat', + 'science_fiction' => 'Fantastyka Naukowa', + 'alternative_health' => 'Zdrowie Alternatywne', + 'fitness' => 'Fitness', + 'medicine' => 'Medycyna', + 'mental_health' => 'Zdrowie Psychiczne', + 'nutrition' => 'Odżywianie', + 'sexuality' => 'Seksualność', + 'education_for_kids' => 'Edukacja dla Dzieci', + 'parenting' => 'Rodzicielstwo', + 'pets_and_animals' => 'Zwierzęta i Zwierzęta Domowe', + 'stories_for_kids' => 'Historie dla Dzieci', + 'animation_and_manga' => 'Animacja i manga', + 'automotive' => 'Motoryzacja', + 'aviation' => 'Lotnictwo', + 'crafts' => 'Rzemieślnictwo', + 'games' => 'Gry', + 'hobbies' => 'Hobby', + 'home_and_garden' => 'Dom i Ogród', + 'video_games' => 'Gry Wideo', + 'music_commentary' => 'Komentarz Muzyczny', + 'music_history' => 'Historia Muzyki', + 'music_interviews' => 'Wywiady Muzyczne', + 'business_news' => 'Wiadomości Biznesowe', + 'daily_news' => 'Codzienne Wiadomości', + 'entertainment_news' => 'Wiadomości Rozrywkowe', + 'news_commentary' => 'Komentarz Wiadomości', + 'politics' => 'Polityka', + 'sports_news' => 'Wiadomości Sportowe', + 'tech_news' => 'Wiadomości Techniczne', + 'buddhism' => 'Buddyzm', + 'christianity' => 'Chrześcijaństwo', + 'hinduism' => 'Hinduizm', + 'islam' => 'Islam', + 'judaism' => 'Judaizm', + 'religion' => 'Religia', + 'spirituality' => 'Duchowość', + 'astronomy' => 'Astronomia', + 'chemistry' => 'Chemia', + 'earth_sciences' => 'Nauka o Ziemi', + 'life_sciences' => 'Nauki o Życiu', + 'mathematics' => 'Matematyka', + 'natural_sciences' => 'Nauki Przyrodnicze', + 'nature' => 'Natura', + 'physics' => 'Fizyka', + 'social_sciences' => 'Nauki Społeczne', + 'documentary' => 'Dokument', + 'personal_journals' => 'Dzienniki Osobiste', + 'philosophy' => 'Filozofia', + 'places_and_travel' => 'Miejsca i podróże', + 'relationships' => 'Związki', + 'baseball' => 'Baseball', + 'basketball' => 'Koszykówka', + 'cricket' => 'Krykiet', + 'fantasy_sports' => 'Sporty fantasy', + 'football' => 'Futbol', + 'golf' => 'Golf', + 'hockey' => 'Hokej', + 'rugby' => 'Rugby', + 'running' => 'Bieg', + 'soccer' => 'Piłka nożna', + 'swimming' => 'Pływanie', + 'tennis' => 'Tenis', + 'volleyball' => 'Siatkówka', + 'wilderness' => 'Dzika przyroda', + 'wrestling' => 'Zapasy', + 'after_shows' => 'Po audycji', + 'film_history' => 'Historia Filmu', + 'film_interviews' => 'Wywiady filmowe', + 'film_reviews' => 'Recenzje filmów', + 'tv_reviews' => 'Recenzje telewizyjne', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Powrót do panelu podcastów', + 'post' => 'Twój wpis ogłoszeniowy', + 'post_hint' => + "Napisz wiadomość, aby ogłosić publikację podcastu. Wiadomość będzie wyświetlana na stronie głównej podcastu.", + 'message_placeholder' => 'Napisz swoją wiadomość…', + 'submit' => 'Opublikuj', + 'publication_date' => 'Data publikacji', + 'publication_method' => [ + 'now' => 'Teraz', + 'schedule' => 'Zaplanuj', + ], + 'scheduled_publication_date' => 'Planowana data publikacji', + 'scheduled_publication_date_hint' => + 'Możesz zaplanować wydanie odcinka, ustawiając przyszłą datę publikacji. To pole musi być sformatowane jako YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edytuj publikację', + 'cancel_publication' => 'Anuluj publikację', + 'message_warning' => 'Nie napisałeś wiadomości do swojego wpisu ogłoszeniowego!', + 'message_warning_hint' => 'Posiadanie wiadomości zwiększa zaangażowanie społeczne, co skutkuje lepszą widocznością Twojego podcastu.', + 'message_warning_submit' => 'Opublikuj mimo to', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'tryb szkicu', + 'not_published' => 'Ten podcast nie został jeszcze opublikowany.', + 'scheduled' => 'Ten podcast jest zaplanowany do publikacji na {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Usunięcie podcastu spowoduje usunięcie wszystkich odcinków, plików multimedialnych, postów i analityk z nim związanych. Ta akcja jest nieodwracalna, nie będziesz w stanie odzyskać tego wszystkiego później.", + 'understand' => 'Rozumiem, chciałbym, aby podcast został trwale usunięty', + 'submit' => 'Usuń', + ], + 'by' => 'Przez {publisher}', + 'season' => 'Sezon {seasonNumber}', + 'list_of_episodes_year' => '{year} odcinki ({episodeCount})', + 'list_of_episodes_season' => + 'Sezon {seasonNumber} odcinki ({episodeCount})', + 'no_episode' => 'Nie znaleziono odcinków!', + 'follow' => 'Obserwuj', + 'followers' => '{numberOfFollowers, plural, + one {# polubienie} + few {# polubienia} + other {# polubień} + }', + 'posts' => '{numberOfPosts, plural, + one {# osoba} + few {# osoby} + other {# osób} + }', + 'activity' => 'Aktywność', + 'episodes' => 'Odcinki', + 'sponsor' => 'Sponsoruj', + 'funding_links' => 'Linki finansowania dla {podcastTitle}', + 'find_on' => 'Znajdź {podcastTitle} na', + 'listen_on' => 'Słuchaj na', +]; diff --git a/modules/Admin/Language/pl/PodcastNavigation.php b/modules/Admin/Language/pl/PodcastNavigation.php new file mode 100644 index 00000000..ff8066e2 --- /dev/null +++ b/modules/Admin/Language/pl/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Idź do strony podcastu', + 'rss_feed' => 'Kanał RSS', + 'dashboard' => 'Pulpit podcastu', + 'podcast-view' => 'Początek', + 'podcast-edit' => 'Edytuj podcast', + 'podcast-persons-manage' => 'Zarządzaj osobami', + 'podcast-imports' => 'Importy podcastów', + 'podcast-imports-sync' => 'Synchronizuj kanały', + 'episodes' => 'Odcinki', + 'episode-list' => 'Wszystkie odcinki', + 'episode-create' => 'Nowy odcinek', + 'analytics' => 'Analityka', + 'podcast-analytics' => 'Przegląd odbiorców', + 'podcast-analytics-webpages' => 'Odwiedziny stron internetowych', + 'podcast-analytics-locations' => 'Lokalizacje', + 'podcast-analytics-unique-listeners' => 'Unikalni słuchacze', + 'podcast-analytics-players' => 'Odtwarzacze', + 'podcast-analytics-listening-time' => 'Czas odsłuchu', + 'podcast-analytics-time-periods' => 'Okresy czasu', + 'monetization' => 'Monetyzacja', + 'subscription-list' => 'Wszystkie subskrypcje', + 'subscription-create' => 'Dodaj subskrypcję', + 'contributors' => 'Kontrybutorzy', + 'contributor-list' => 'Wszyscy kontrybutorzy', + 'contributor-add' => 'Dodaj kontrybutora', + 'broadcast' => 'Transmisja', + 'platforms-podcasting' => 'Aplikacje podcastowe', + 'platforms-social' => 'Sieci społecznościowe', + 'platforms-funding' => 'Linki do finansowania', + 'podcast-monetization-other' => 'Inne', +]; diff --git a/modules/Admin/Language/pl/Settings.php b/modules/Admin/Language/pl/Settings.php new file mode 100644 index 00000000..ef20ebf1 --- /dev/null +++ b/modules/Admin/Language/pl/Settings.php @@ -0,0 +1,58 @@ + 'Ustawienia ogólne', + 'instance' => [ + 'title' => 'Instancja', + 'site_icon' => 'Ikona witryny', + 'site_icon_delete' => 'Usuń ikonę witryny', + 'site_icon_hint' => 'Ikony witryny są widoczne na kartach przeglądarki, paskach zakładek oraz po dodaniu witryny jako skrótu na urządzeniach mobilnych.', + 'site_icon_helper' => 'Ikona musi być kwadratowa o szerokości i wysokości co najmniej 512 pikseli.', + 'site_name' => 'Nazwa strony', + 'site_description' => 'Opis strony', + 'submit' => 'Zapisz', + 'editSuccess' => 'Instancja została pomyślnie zaktualizowana!', + 'deleteIconSuccess' => 'Ikona witryny została pomyślnie usunięta!', + ], + 'images' => [ + 'title' => 'Obrazy', + 'subtitle' => 'Tutaj możesz ponownie wygenerować wszystkie obrazy na podstawie przesłanych oryginałów. Do wykorzystania, jeśli okaże się, że brakuje niektórych obrazów. To zadanie może chwilę potrwać.', + 'regenerate' => 'Wygeneruj ponownie obrazy', + 'regenerationSuccess' => 'Wszystkie obrazy zostały pomyślnie wygenerowane ponownie!', + ], + 'housekeeping' => [ + 'title' => 'Porządkowanie', + 'subtitle' => 'Wykonuje różne zadania porządkowe. Użyj tej funkcji jeśli kiedykolwiek napotkasz problemy z plikami multimedialnymi lub integralnością danych. Te zadania mogą chwilę potrwać.', + 'reset_counts' => 'Zresetuj liczniki', + 'reset_counts_helper' => 'Ta opcja zresetuje i ponownie obliczy wszystkie liczniki danych (liczbę obserwujących, wpisów, komentarzy, …).', + 'rewrite_media' => 'Przepisz metadane multimediów', + 'rewrite_media_helper' => 'Ta opcja usunie wszystkie zbędne pliki multimedialne i odtworzy je (obrazy, pliki audio, transkrypcje, rozdziały, …)', + 'rename_episodes_files' => 'Zmień nazwę plików audio odcinka', + 'rename_episodes_files_hint' => 'Ta opcja zmieni nazwę wszystkich odcinków plików audio na losowy ciąg znaków. Użyj tego, jeśli jeden z Twoich prywatnych odcinków został ujawniony, ponieważ to skutecznie go ukryje.', + 'clear_cache' => 'Wyczyść całą pamięć podręczną', + 'clear_cache_helper' => 'Ta opcja opróżni pamięć podręczną (cache) redis lub zapisywalne/buforowane pliki.', + 'run' => 'Przeprowadź porządkowanie', + 'runSuccess' => 'Porządkowanie zostało przeprowadzone pomyślnie!', + ], + 'theme' => [ + 'title' => 'Motyw', + 'accent_section_title' => 'Kolor akcentu', + 'accent_section_subtitle' => 'Wybierz kolor, aby określić wygląd i styl wszystkich stron publicznych.', + 'pine' => 'Sosna', + 'crimson' => 'Karmazynowy', + 'amber' => 'Bursztyn', + 'lake' => 'Jezioro', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyks', + 'submit' => 'Zapisz', + 'setInstanceThemeSuccess' => 'Motyw został pomyślnie zaktualizowany!', + ], +]; diff --git a/modules/Admin/Language/pl/Soundbite.php b/modules/Admin/Language/pl/Soundbite.php new file mode 100644 index 00000000..32fbc02b --- /dev/null +++ b/modules/Admin/Language/pl/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Zajawki', + 'soundbite' => 'Zajawka', + ], + 'messages' => [ + 'createSuccess' => 'Zajawka została pomyślnie utworzona!', + 'deleteSuccess' => 'Zajawka została pomyślnie usunięta!', + ], + 'form' => [ + 'title' => 'Nowa zajawka', + 'soundbite_title' => 'Tytuł zajawki', + 'start_time' => 'Rozpocznij od', + 'duration' => 'Długość', + 'submit' => 'Stwórz zajawkę', + ], + 'play' => 'Odtwórz zajawkę', + 'stop' => 'Zatrzymaj zajawkę', + 'create' => 'Nowa zajawka', + 'delete' => 'Usuń zajawkę', +]; diff --git a/modules/Admin/Language/pl/Validation.php b/modules/Admin/Language/pl/Validation.php new file mode 100644 index 00000000..258f7119 --- /dev/null +++ b/modules/Admin/Language/pl/Validation.php @@ -0,0 +1,17 @@ + + '{field} nie jest obrazem albo nie jest wystarczająco szeroki lub wysoki.', + 'is_image_ratio' => + '{field} nie jest obrazem albo nie ma właściwych proporcji.', + 'is_json' => '{field} zawiera nieprawidłowy JSON.', +]; diff --git a/modules/Admin/Language/pl/VideoClip.php b/modules/Admin/Language/pl/VideoClip.php new file mode 100644 index 00000000..03453b0e --- /dev/null +++ b/modules/Admin/Language/pl/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Klipy wideo', + 'status' => [ + 'label' => 'Status', + 'queued' => 'w kolejce', + 'queued_hint' => 'Klip czeka na przetworzenie.', + 'pending' => 'oczekuje', + 'pending_hint' => 'Klip zostanie wkrótce wygenerowany.', + 'running' => 'w toku', + 'running_hint' => 'Klip jest generowany.', + 'failed' => 'niepowodzenie', + 'failed_hint' => 'Nie można było wygenerować klipu: błąd skryptu.', + 'passed' => 'powodzenie', + 'passed_hint' => 'Klip został pomyślnie wygenerowany!', + ], + 'clip' => 'Klip', + 'duration' => 'Czas zadania', + ], + 'title' => 'Klip wideo: {videoClipLabel}', + 'download_clip' => 'Pobierz klip', + 'create' => 'Nowy klip wideo', + 'go_to_page' => 'Idź do strony klipu', + 'retry' => 'Ponów generowanie klipu', + 'delete' => 'Usuń klip', + 'logs' => 'Dzienniki zadania', + 'messages' => [ + 'alreadyExistingError' => 'Klip wideo, który próbujesz utworzyć, już istnieje!', + 'addToQueueSuccess' => 'Klip wideo został dodany do kolejki i oczekuje na utworzenie!', + 'deleteSuccess' => 'Klip wideo został pomyślnie usunięty!', + ], + 'format' => [ + 'landscape' => 'Poziomy', + 'portrait' => 'Pionowy', + 'squared' => 'Kwadratowy', + ], + 'form' => [ + 'title' => 'Nowy klip wideo', + 'params_section_title' => 'Parametry klipu wideo', + 'clip_title' => 'Tytuł klipu', + 'format' => [ + 'label' => 'Wybierz format', + 'landscape_hint' => 'W proporcji 16:9, filmy w orientacji poziomej są świetne do PeerTube, Youtube i Vimeo.', + 'portrait_hint' => 'W proporcji 9:16, filmy pionowe świetnie nadają się do TikTok, krótkich filmów na YouTube i Stories na Instagramie.', + 'squared_hint' => 'W proporcji 1:1, kwadratowe filmy są świetne dla Mastodon, Facebooka, Twittera i LinkedIn.', + ], + 'theme' => 'Wybierz motyw', + 'start_time' => 'Rozpocznij od', + 'duration' => 'Długość', + 'trim_start' => 'Przytnij początek', + 'trim_end' => 'Przytnij koniec', + 'submit' => 'Stwórz klip wideo', + ], + 'requirements' => [ + 'title' => 'Brakujące wymagania', + 'missing' => 'Brakuje wymaganych elementów. Upewnij się, że dodałeś wszystkie wymagane elementy, aby móc tworzyć wideo do tego odcinka!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Biblioteka Freetype dla GD', + 'transcript' => 'Plik z transkrypcją (.srt)', + ], +]; diff --git a/modules/Admin/Language/pt-br/AboutCastopod.php b/modules/Admin/Language/pt-br/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/pt-br/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/pt-br/Breadcrumb.php b/modules/Admin/Language/pt-br/Breadcrumb.php new file mode 100644 index 00000000..7ca40d76 --- /dev/null +++ b/modules/Admin/Language/pt-br/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Início', + 'podcasts' => 'podcasts', + 'episodes' => 'episódios', + 'subscriptions' => 'assinaturas', + 'contributors' => 'contribuidores', + 'pages' => 'páginas', + 'settings' => 'configurações', + 'theme' => 'tema', + 'about' => 'sobre', + 'add' => 'adicionar', + 'new' => 'novo', + 'edit' => 'editar', + 'persons' => 'pessoas', + 'publish' => 'publicar', + 'publish-edit' => 'editar publicação', + 'publish-date-edit' => 'editar data de publicação', + 'unpublish' => 'despublicar', + 'delete' => 'excluir', + 'remove' => 'remover', + 'fediverse' => 'fediverso', + 'blocked-actors' => 'atores bloqueados', + 'blocked-domains' => 'domínios bloqueados', + 'users' => 'usuários', + 'my-account' => 'minha conta', + 'change-password' => 'alterar senha', + 'imports' => 'importações', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'plataformas', + 'social' => 'redes sociais', + 'funding' => 'financiamento', + 'monetization-other' => 'other monetization', + 'analytics' => 'estatísticas', + 'locations' => 'localizações', + 'webpages' => 'páginas da web', + 'unique-listeners' => 'ouvintes únicos', + 'players' => 'players', + 'listening-time' => 'tempo de escuta', + 'time-periods' => 'períodos de tempo', + 'soundbites' => 'clipes de áudio', + 'video-clips' => 'clipes de vídeo', + 'embed' => 'player incorporável', + 'notifications' => 'notificações', + 'suspend' => 'suspender', +]; diff --git a/modules/Admin/Language/pt-br/Charts.php b/modules/Admin/Language/pt-br/Charts.php new file mode 100644 index 00000000..9a84d031 --- /dev/null +++ b/modules/Admin/Language/pt-br/Charts.php @@ -0,0 +1,41 @@ + 'Downloads de episódios por serviço (na última semana)', + 'by_player_weekly' => 'Downloads de episódios por player (na última semana)', + 'by_player_yearly' => 'Downloads de episódios por player (no último ano)', + 'by_device_weekly' => 'Downloads de episódios por dispositivo (na última semana)', + 'by_os_weekly' => 'Downloads de episódios por O.S. (na última semana)', + 'podcast_by_region' => 'Downloads de episódios por região (na última semana)', + 'unique_daily_listeners' => 'Ouvintes únicos diários', + 'unique_monthly_listeners' => 'Ouvintes únicos mensais', + 'by_browser' => 'Tráfego de páginas da web por navegador (na última semana)', + 'podcast_by_day' => 'Downloads diários de episódios', + 'podcast_by_month' => 'Downloads mensais de episódios', + 'episode_by_day' => 'Downloads diários do episódio (primeiros 60 dias)', + 'episode_by_month' => 'Downloads mensais do episódio', + 'episodes_by_day' => + 'Downloads dos últimos 5 episódios (durante seus primeiros 60 dias)', + 'by_country_weekly' => 'Downloads dos episódios por país (na última semana)', + 'by_country_yearly' => 'Downloads dos episódios por país (no último ano)', + 'by_domain_weekly' => 'Tráfego de páginas da web por origem (na última semana)', + 'by_domain_yearly' => 'Tráfego de páginas da web por origem (no último ano)', + 'by_entry_page' => 'Tráfego de páginas da web por página de destino (na última semana)', + 'podcast_bots' => 'Bots (rastreadores)', + 'daily_listening_time' => 'Tempo de escuta cumulativo diário', + 'monthly_listening_time' => 'Tempo de escuta cumulativo mensal', + 'by_weekday' => 'Por dia da semana (para os últimos 60 dias)', + 'by_hour' => 'Por horário do dia (para os últimos 60 dias)', + 'podcast_by_bandwidth' => 'Largura de banda usada diária (em MB)', + 'total_storage_by_month' => 'Armazenamento mensal (em MB)', + 'total_bandwidth_by_month' => 'Largura de banda usada mensalmente (em MB)', + 'total_bandwidth_by_month_limit' => 'Limitado a {totalBandwidth} por mês', +]; diff --git a/modules/Admin/Language/pt-br/Common.php b/modules/Admin/Language/pt-br/Common.php new file mode 100644 index 00000000..f82a5109 --- /dev/null +++ b/modules/Admin/Language/pt-br/Common.php @@ -0,0 +1,52 @@ + 'Sim', + 'no' => 'Não', + 'cancel' => 'Cancelar', + 'optional' => 'Opcional', + 'more' => 'Mais', + 'no_data' => 'Nenhum dado encontrado!', + 'close' => 'Fechar', + 'edit' => 'Editar', + 'copy' => 'Copiar', + 'copied' => 'Copiado!', + 'home' => 'Início', + 'explicit' => 'Explícito', + 'powered_by' => 'Desenvolvido por {castopod}', + 'actions' => 'Ações', + 'pageInfo' => 'Página {currentPage} de {pageCount}', + 'go_back' => 'Voltar', + 'forms' => [ + 'editor' => [ + 'write' => 'Escrever', + 'preview' => 'Visualizar', + 'help' => 'Desenvolvido em Markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Clique para selecionar', + 'loadingText' => 'Carregando…', + 'noResultsText' => 'Nenhum resultado encontrado', + 'noChoicesText' => 'Nenhuma escolha possível', + 'maxItemText' => 'Não é possível adicionar mais itens', + ], + 'upload_file' => 'Enviar um arquivo', + 'remote_url' => 'URL remota', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Reproduzir', + 'playing' => 'Reproduzindo', + ], + 'size_limit' => 'Limite de tamanho: {0}.', + 'choose_interact' => 'Escolha como interagir', + 'view' => 'Visualizar', +]; diff --git a/modules/Admin/Language/pt-br/Countries.php b/modules/Admin/Language/pt-br/Countries.php new file mode 100644 index 00000000..95698b52 --- /dev/null +++ b/modules/Admin/Language/pt-br/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Emirados Árabes Unidos', + 'AF' => 'Afeganistão', + 'AG' => 'Antígua e Barbuda', + 'AI' => 'Anguila', + 'AL' => 'Albânia', + 'AM' => 'Armênia', + 'AO' => 'Angola', + 'AQ' => 'Antártica', + 'AR' => 'Argentina', + 'AS' => 'Samoa Americana', + 'AT' => 'Áustria', + 'AU' => 'Austrália', + 'AW' => 'Aruba', + 'AX' => 'Ilhas Åland', + 'AZ' => 'Azerbaijão', + 'BA' => 'Bósnia e Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Bélgica', + 'BF' => 'Burquina Faso', + 'BG' => 'Bulgária', + 'BH' => 'Bahrein', + 'BI' => 'Burundi', + 'BJ' => 'Benim', + 'BL' => 'São Bartolomeu', + 'BM' => 'Bermudas', + 'BN' => 'Brunei', + 'BO' => 'Bolívia, Estado Plurinacional da', + 'BQ' => 'Bonaire, Santo Eustáquio e Saba', + 'BR' => 'Brasil', + 'BS' => 'Bahamas', + 'BT' => 'Butão', + 'BV' => 'Ilha Bouvet', + 'BW' => 'Botsuana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canadá', + 'CC' => 'Ilhas Cocos (Keeling)', + 'CD' => 'Congo, República Democrática do', + 'CF' => 'República Centro-Africana', + 'CG' => 'Congo', + 'CH' => 'Suíça', + 'CI' => "Costa do Marfim", + 'CK' => 'Ilhas Cook', + 'CL' => 'Chile', + 'CM' => 'Camarões', + 'CN' => 'China', + 'CO' => 'Colômbia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cabo Verde', + 'CW' => 'Curaçau', + 'CX' => 'Ilha Christmas', + 'CY' => 'Chipre', + 'CZ' => 'Tchéquia', + 'DE' => 'Alemanha', + 'DJ' => 'Djibouti', + 'DK' => 'Dinamarca', + 'DM' => 'Dominica', + 'DO' => 'República Dominicana', + 'DZ' => 'Argélia', + 'EC' => 'Equador', + 'EE' => 'Estônia', + 'EG' => 'Egito', + 'EH' => 'Sara Ocidental', + 'ER' => 'Eritréia', + 'ES' => 'Espanha', + 'ET' => 'Etiópia', + 'FI' => 'Finlândia', + 'FJ' => 'Fiji', + 'FK' => 'Ilhas Falkland (Malvinas)', + 'FM' => 'Micronésia, Estados Federados da', + 'FO' => 'Ilhas Feroe', + 'FR' => 'França', + 'GA' => 'Gabão', + 'GB' => 'Reino Unido', + 'GD' => 'Granada', + 'GE' => 'Geórgia', + 'GF' => 'Guiana Francesa', + 'GG' => 'Guernsey', + 'GH' => 'Gana', + 'GI' => 'Gibraltar', + 'GL' => 'Groelândia', + 'GM' => 'Gâmbia', + 'GN' => 'Guiné', + 'GP' => 'Guadalupe', + 'GQ' => 'Guiné Equatorial', + 'GR' => 'Grécia', + 'GS' => 'Ilhas Geórgia do Sul e Sandwich do Sul', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guiné-Bissau', + 'GY' => 'Guiana', + 'HK' => 'Hong Kong', + 'HM' => 'Ilha Heard e Ilhas McDonald', + 'HN' => 'Honduras', + 'HR' => 'Croácia', + 'HT' => 'Haiti', + 'HU' => 'Hungria', + 'ID' => 'Indonésia', + 'IE' => 'Irlanda', + 'IL' => 'Israel', + 'IM' => 'Ilha de Man', + 'IN' => 'Índia', + 'IO' => 'Território Britânico do Oceano Índico', + 'IQ' => 'Iraque', + 'IR' => 'Irã, República Islâmica do', + 'IS' => 'Islândia', + 'IT' => 'Itália', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordânia', + 'JP' => 'Japão', + 'KE' => 'Quênia', + 'KG' => 'Quirguistão', + 'KH' => 'Camboja', + 'KI' => 'Kiribati', + 'KM' => 'Comores', + 'KN' => 'São Cristóvão e Névis', + 'KP' => "Coréia, República Popular Democrática da", + 'KR' => 'Coréia, República da', + 'KW' => 'Kuwait', + 'KY' => 'Ilhas Cayman', + 'KZ' => 'Cazaquistão', + 'LA' => "Laos, República Democrática Popular do", + 'LB' => 'Líbano', + 'LC' => 'Santa Lúcia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Libéria', + 'LS' => 'Lesoto', + 'LT' => 'Lituânia', + 'LU' => 'Luxemburgo', + 'LV' => 'Letônia', + 'LY' => 'Líbia', + 'MA' => 'Marrocos', + 'MC' => 'Mônaco', + 'MD' => 'Moldávia, República da', + 'ME' => 'Montenegro', + 'MF' => 'São Martinho (França)', + 'MG' => 'Madagáscar', + 'MH' => 'Ilhas Marshall', + 'MK' => 'Macedônia do Norte', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongólia', + 'MO' => 'Macau', + 'MP' => 'Ilhas Marianas do Norte', + 'MQ' => 'Martinica', + 'MR' => 'Mauritânia', + 'MS' => 'Monserrate', + 'MT' => 'Malta', + 'MU' => 'Maurício', + 'MV' => 'Maldivas', + 'MW' => 'Malawi', + 'MX' => 'México', + 'MY' => 'Malásia', + 'MZ' => 'Moçambique', + 'N/A' => 'Não Aplicável (IP local…)', + 'NA' => 'Namíbia', + 'NC' => 'Nova Caledônia', + 'NE' => 'Níger', + 'NF' => 'Ilha Norfolk', + 'NG' => 'Nigéria', + 'NI' => 'Nicarágua', + 'NL' => 'Países Baixos (Holanda)', + 'NO' => 'Noruega', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nova Zelândia', + 'OM' => 'Omã', + 'PA' => 'Panamá', + 'PE' => 'Peru', + 'PF' => 'Polinésia Francesa', + 'PG' => 'Papua Nova Guiné', + 'PH' => 'Filipinas', + 'PK' => 'Paquistão', + 'PL' => 'Polônia', + 'PM' => 'São Pedro e Miquelão', + 'PN' => 'Ilhas Pitcairn', + 'PR' => 'Porto Rico', + 'PS' => 'Palestina, Estado da', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguai', + 'QA' => 'Qatar', + 'RE' => 'Reunião', + 'RO' => 'Romênia', + 'RS' => 'Sérvia', + 'RU' => 'Federação Russa', + 'RW' => 'Ruanda', + 'SA' => 'Arábia Saudita', + 'SB' => 'Ilhas Salomão', + 'SC' => 'Seicheles', + 'SD' => 'Sudão', + 'SE' => 'Suécia', + 'SG' => 'Singapura', + 'SH' => 'Santa Helena, Ascensão e Tristão da Cunha', + 'SI' => 'Eslovênia', + 'SJ' => 'Svalbard e Jan Mayen', + 'SK' => 'Eslováquia', + 'SL' => 'Serra Leoa', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somália', + 'SR' => 'Suriname', + 'SS' => 'Sudão do Sul', + 'ST' => 'São Tomé e Príncipe', + 'SV' => 'El Salvador', + 'SX' => 'São Martinho (Países Baixos)', + 'SY' => 'Síria, República Árabe', + 'SZ' => 'Essuatíni', + 'TC' => 'Ilhas Turcas e Caicos', + 'TD' => 'Chade', + 'TF' => 'Terras Austrais e Antárticas Francesas', + 'TG' => 'Togo', + 'TH' => 'Tailândia', + 'TJ' => 'Tajiquistão', + 'TK' => 'Toquelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turcomenistão', + 'TN' => 'Tunísia', + 'TO' => 'Tonga', + 'TR' => 'Turquia', + 'TT' => 'Trindade e Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Província da China', + 'TZ' => 'Tanzânia, República Unida da', + 'UA' => 'Ucrânia', + 'UG' => 'Uganda', + 'UM' => 'Ilhas Menores Distantes dos Estados Unidos', + 'US' => 'Estados Unidos', + 'UY' => 'Uruguai', + 'UZ' => 'Uzbequistão', + 'VA' => 'Santa Sé (Estado da Cidade do Vaticano)', + 'VC' => 'São Vicente e Granadinas', + 'VE' => 'Venezuela, República Bolivariana da', + 'VG' => 'Ilhas Virgens Britânicas', + 'VI' => 'Ilhas Virgens Americanas', + 'VN' => 'Vietnã', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis e Futuna', + 'WS' => 'Samoa', + 'YE' => 'Iémen', + 'YT' => 'Mayotte', + 'ZA' => 'África do Sul', + 'ZM' => 'Zâmbia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/pt-br/Dashboard.php b/modules/Admin/Language/pt-br/Dashboard.php new file mode 100644 index 00000000..0ce3a157 --- /dev/null +++ b/modules/Admin/Language/pt-br/Dashboard.php @@ -0,0 +1,28 @@ + 'Painel de administração', + 'welcome_message' => 'Bem-vindo à área de administração!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Nenhum podcast publicado', + 'last_published' => 'Última publicação em {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episódios', + 'not_found' => 'Nenhum episódio publicado', + 'last_published' => 'Última publicação em {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Armazenamento', + 'subtitle' => '{totalUploaded} de {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/pt-br/Episode.php b/modules/Admin/Language/pt-br/Episode.php new file mode 100644 index 00000000..427f9092 --- /dev/null +++ b/modules/Admin/Language/pt-br/Episode.php @@ -0,0 +1,225 @@ + 'Temporada {seasonNumber}', + 'season_abbr' => 'T{seasonNumber}', + 'number' => 'Episódio {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Temporada {seasonNumber} episódio {episodeNumber}', + 'season_episode_abbr' => 'T{seasonNumber}:E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comentário} + other {# comentários} + }', + 'all_podcast_episodes' => 'Todos os episódios de podcast', + 'back_to_podcast' => 'Voltar para o podcast', + 'edit' => 'Editar', + 'preview' => 'Pré-visualizar', + 'publish' => 'Publicar', + 'publish_edit' => 'Editar publicação', + 'publish_date_edit' => 'Editar data de publicação', + 'unpublish' => 'Despublicar', + 'publish_error' => 'O episódio já está publicado.', + 'publish_edit_error' => 'O episódio já está publicado.', + 'publish_cancel_error' => 'O episódio já está publicado.', + 'publish_date_edit_error' => 'Episódio ainda não foi publicado, você não pode editar a data de publicação dele.', + 'publish_date_edit_future_error' => 'A data de publicação do episódio só pode ser definida para data passada! Se você deseja reagendá-la, cancele a publicação primeiro.', + 'publish_date_edit_success' => 'A data de publicação do episódio foi atualizada com sucesso!', + 'unpublish_error' => 'O episódio não está publicado.', + 'delete' => 'Excluir', + 'go_to_page' => 'Ir para a página', + 'create' => 'Adicionar um episódio', + 'publication_status' => [ + 'published' => 'Publicado', + 'with_podcast' => 'Publicado', + 'scheduled' => 'Programado', + 'not_published' => 'Não publicado', + ], + 'with_podcast_hint' => 'A ser publicado ao mesmo tempo que o podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Buscar um episódio', + 'clear' => 'Limpar busca', + 'submit' => 'Buscar', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episódio} + other {# episódios} + }', + 'episode' => 'Episódio', + 'visibility' => 'Visibilidade', + 'downloads' => 'Downloads', + 'comments' => 'Comentários', + 'actions' => 'Ações', + ], + 'messages' => [ + 'createSuccess' => 'Episódio foi criado com sucesso!', + 'editSuccess' => 'Episódio foi atualizado com sucesso!', + 'publishSuccess' => '{publication_status, select, + published {Episódio publicado com sucesso!} + scheduled {Publicação de episódios agendada com sucesso!} + with_podcast {Este episódio será publicado ao mesmo tempo que o podcast.} + other {Este episódio não foi publicado.} + }', + 'publishCancelSuccess' => 'Publicação do episódio cancelada!', + 'unpublishBeforeDeleteTip' => 'Você deve despublicar o episódio antes de excluí-lo.', + 'scheduleDateError' => 'Data de agendamento deve ser definida!', + 'deletePublishedEpisodeError' => 'Por favor, despublique o episódio antes de excluí-lo.', + 'deleteSuccess' => 'Episódio excluído com sucesso!', + 'deleteError' => 'Falha ao excluir o episódio {type, select, + transcript {transcrição} + chapters {capítulos} + image {cupa} + audio {áudio} + other {mídia} + }.', + 'deleteFileError' => 'Falha ao excluir o arquivo de {type, select, + transcript {transcrição} + chapters {capítulos} + image {capa} + audio {áudio} + other {mídia} + }arquivo {file_key}. Você pode removê-lo manualmente do seu disco.', + 'sameSlugError' => 'Um episódio com o slug escolhido já existe.', + ], + 'form' => [ + 'file_size_error' => + 'O tamanho do seu arquivo é muito grande! Tamanho máximo é {0}. Aumente os valores `memory_limit`, `upload_max_filesize` e `post_max_size` no seu arquivo de configuração do php, em seguida, reinicie seu servidor web para enviar seu arquivo.', + 'audio_file' => 'Arquivo de áudio', + 'audio_file_hint' => 'Escolha um arquivo de áudio .mp3 ou .m4a.', + 'info_section_title' => 'Informação do episódio', + 'cover' => 'Capa de episódio', + 'cover_hint' => + 'Se você não definir uma capa, a capa do podcast será usada no lugar.', + 'cover_size_hint' => 'A capa deve ser quadrada e ter pelo menos 1400px de largura e altura.', + 'title' => 'Título', + 'title_hint' => + 'Deve conter um nome de episódio claro e conciso. Não especifique o número de episódio ou de temporada aqui.', + 'permalink' => 'Link permanente', + 'season_number' => 'Temporada', + 'episode_number' => 'Episódio', + 'type' => [ + 'label' => 'Tipo', + 'full' => 'Completo', + 'full_hint' => 'Conteúdo completo (o episódio)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Conteúdo promocional curto que representa uma prévia do podcast', + 'bonus' => 'Bônus', + 'bonus_hint' => 'Conteúdo extra para o podcast (por exemplo, informações nos bastidores ou entrevistas com o elenco) ou conteúdo promocional com outro podcast', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episódio deve estar acessível apenas para assinantes premium', + 'parental_advisory' => [ + 'label' => 'Aviso aos pais', + 'hint' => 'O episódio contém conteúdo explícito?', + 'undefined' => 'não definido', + 'clean' => 'Limpo', + 'explicit' => 'Explícito', + ], + 'show_notes_section_title' => 'Mostrar notas', + 'show_notes_section_subtitle' => + 'Até 4000 caracteres, seja claro e conciso. As notas do episódio ajudam aos ouvintes em potencial a encontrar o episódio.', + 'description' => 'Descrição', + 'description_footer' => 'Rodapé da descrição', + 'description_footer_hint' => + 'Este texto é adicionado no final de cada descrição de episódio, é um bom lugar para inserir seus links sociais por exemplo.', + 'additional_files_section_title' => 'Arquivos adicionais', + 'additional_files_section_subtitle' => + 'Estes arquivos podem ser usados por outras plataformas para fornecer uma melhor experiência ao seu público. Veja o {podcastNamespaceLink} para mais informações.', + 'location_section_title' => 'Localização', + 'location_section_subtitle' => 'Sobre que lugar é este episódio?', + 'location_name' => 'Nome ou endereço da localização', + 'location_name_hint' => 'Esta pode ser uma localização real ou fictícia', + 'transcript' => 'Transcrição (legendas / legendas ocultas)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Baixar transcrição', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'URL remoto para transcrição', + 'transcript_file_delete' => 'Excluir arquivo de transcrição', + 'chapters' => 'Capítulos', + 'chapters_hint' => 'Arquivo deve estar no formato de Capítulos JSON.', + 'chapters_download' => 'Baixar capítulos', + 'chapters_file' => 'Arquivo de capítulos', + 'chapters_remote_url' => 'URL remoto para o arquivo de capítulos', + 'chapters_file_delete' => 'Excluir arquivo de capítulos', + 'advanced_section_title' => 'Parâmetros avançados', + 'advanced_section_subtitle' => + 'Se você precisa de tags RSS que Castopod não lida, defina-as aqui.', + 'custom_rss' => 'Tags RSS personalizadas para o episódio', + 'custom_rss_hint' => 'Isso será injetado dentro da tag ❬item❭.', + 'block' => 'O episódio deve ser ocultado dos catálogos públicos', + 'block_hint' => + 'O status do episódio: ativar isso impede que o episódio apareça em Apple Podcasts, Google Podcasts e qualquer aplicativo de terceiros que extraia programas desses diretórios. (Não garantido)', + 'submit_create' => 'Criar episódio', + 'submit_edit' => 'Salvar episódio', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Voltar ao painel do episódio', + 'post' => 'Sua mensagem de publicação', + 'post_hint' => + "Escreva uma mensagem para anunciar a publicação do seu episódio. A mensagem será transmitida a todos os seus seguidores no fediverso e será destacada na página inicial de seu podcast.", + 'message_placeholder' => 'Escreva a sua mensagem…', + 'publication_date' => 'Data de publicação', + 'publication_method' => [ + 'now' => 'Agora', + 'schedule' => 'Programar', + 'with_podcast' => 'Publicar juntamente com o podcast', + ], + 'scheduled_publication_date' => 'Data de publicação programada', + 'scheduled_publication_date_clear' => 'Limpar data de publicação', + 'scheduled_publication_date_hint' => + 'Você pode agendar a liberação do episódio definindo uma data de publicação futura. Este campo deve ser formatado como YYYY-MM-DD HH:mm', + 'submit' => 'Publicar', + 'submit_edit' => 'Editar publicação', + 'cancel_publication' => 'Cancelar publicação', + 'message_warning' => 'Você não escreveu uma mensagem para o anúncio do episódio!', + 'message_warning_hint' => 'Ter uma mensagem aumenta o engajamento social, resultando em uma melhor visibilidade do seu episódio.', + 'message_warning_submit' => 'Publicar mesmo assim', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nova data de publicação', + 'new_publication_date_hint' => 'Deve ser definido como uma data passada.', + 'submit' => 'Editar data de publicação', + ], + 'unpublish_form' => [ + 'disclaimer' => + "O cancelamento da publicação do episódio excluirá todos os comentários e publicações associados a ele e o removerá do feed RSS do podcast.", + 'understand' => 'Eu entendo, eu quero despublicar o episódio', + 'submit' => 'Despublicar', + ], + 'delete_form' => [ + 'disclaimer' => + "Excluir o episódio irá excluir todos os arquivos de mídia, comentários, clipes de vídeo e clipes de áudio associados a ele.", + 'understand' => 'Eu entendo, eu quero excluir o episódio', + 'submit' => 'Excluir', + ], + 'embed' => [ + 'title' => 'Player incorporável', + 'label' => + 'Escolha uma cor do tema, copie o player incorporável para a área de transferência, e cole-o em seu site.', + 'clipboard_iframe' => 'Copiar player incorporável para área de transferência', + 'clipboard_url' => 'Copiar endereço para área de transferência', + 'dark' => 'Escuro', + 'dark-transparent' => 'Escuro translúcido', + 'light' => 'Claro', + 'light-transparent' => 'Claro translúcido', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'modo rascunho', + 'text' => '{publication_status, select, + published {Esse episódio ainda não foi publicado.} + scheduled {Esse episódio está agendado para publicação em {publication_date}.} + with_podcast {Esse episódio será publicado ao mesmo tempo que o podcast. .} + other {Esse episódio ainda não foi publicado.} + }', + 'preview' => 'Pré-visualizar', + ], +]; diff --git a/modules/Admin/Language/pt-br/EpisodeNavigation.php b/modules/Admin/Language/pt-br/EpisodeNavigation.php new file mode 100644 index 00000000..7c7fd16a --- /dev/null +++ b/modules/Admin/Language/pt-br/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Ver página do episódio', + 'dashboard' => 'Painel do episódio', + 'episode-view' => 'Início', + 'episode-edit' => 'Editar episódio', + 'episode-persons-manage' => 'Gerenciar pessoas', + 'embed-add' => 'Player incorporável', + 'clips' => 'Clipes', + 'video-clips-list' => 'Clipes de vídeo', + 'video-clips-create' => 'Novo clipe de vídeo', + 'soundbites-list' => 'Clipes de áudio', + 'soundbites-create' => 'Novo clipe de áudio', +]; diff --git a/modules/Admin/Language/pt-br/Fediverse.php b/modules/Admin/Language/pt-br/Fediverse.php new file mode 100644 index 00000000..bd462bf6 --- /dev/null +++ b/modules/Admin/Language/pt-br/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'A conta não pôde ser encontrada!', + 'blockActorSuccess' => '{actor} foi bloqueado!', + 'unblockActorSuccess' => 'A pessoa foi desbloqueada!', + 'blockDomainSuccess' => '{domain} foi bloqueado!', + 'unblockDomainSuccess' => '{domain} foi desbloqueado!', + ], + 'blocked_actors' => 'Contas bloqueadas', + 'blocked_domains' => 'Domínios bloqueados', + 'block_lists_form' => [ + 'handle' => 'Identificador da conta', + 'handle_hint' => 'Insira a conta @usuário@domínio.', + 'domain' => 'Nome do domínio', + 'submit' => 'Bloquear!', + ], + 'list' => [ + 'actor' => 'Conta', + 'domain' => 'Nome do domínio', + 'unblock' => 'Desbloquear', + ], +]; diff --git a/modules/Admin/Language/pt-br/Home.php b/modules/Admin/Language/pt-br/Home.php new file mode 100644 index 00000000..5c085046 --- /dev/null +++ b/modules/Admin/Language/pt-br/Home.php @@ -0,0 +1,14 @@ + 'Todos os podcasts', + 'no_podcast' => 'Nenhum podcast encontrado', +]; diff --git a/modules/Admin/Language/pt-br/Install.php b/modules/Admin/Language/pt-br/Install.php new file mode 100644 index 00000000..cb5fd72b --- /dev/null +++ b/modules/Admin/Language/pt-br/Install.php @@ -0,0 +1,61 @@ + 'Configuração manual', + 'manual_config_subtitle' => + 'Crie um arquivo `.env` com suas configurações e atualize a página para continuar a instalação.', + 'form' => [ + 'instance_config' => 'Configuração da instância', + 'hostname' => 'Hostname', + 'media_base_url' => 'URL de banco de mídia', + 'media_base_url_hint' => + 'Se você usar um CDN e/ou um serviço de estatísticas externo, você pode os configurar aqui.', + 'admin_gateway' => 'Gateway de administrador', + 'admin_gateway_hint' => + 'O caminho para acessar a área admin (ex. https://example.com/cp-admin). Ele é definido por padrão como cp-admin, recomendamos que você a altere por razões de segurança.', + 'auth_gateway' => 'Gateway de autenticação', + 'auth_gateway_hint' => + 'O caminho para acessar as páginas de autenticação (ex. https://example.com/cp-auth). Ele é definido por padrão como cp-auth, recomendamos que você a altere por motivos de segurança.', + 'database_config' => 'Configuração do banco de dados', + 'database_config_hint' => + 'O Castopod precisa se conectar ao seu banco de dados MySQL (ou MariaDB). Se você não tem essas informações necessárias, entre em contato com o administrador do servidor.', + 'db_hostname' => 'Hostname do banco de dados', + 'db_name' => 'Nome do banco de dados', + 'db_username' => 'Nome de usuário do banco de dados', + 'db_password' => 'Senha do banco de dados', + 'db_prefix' => 'Prefixo do banco de dados', + 'db_prefix_hint' => + "O prefixo dos nomes das tabelas do Castopod, deixe como está se você não souber o que significa.", + 'cache_config' => 'Configuração de cache', + 'cache_config_hint' => + 'Escolha seu manipulador de cache preferido. Deixe-o com o valor padrão se você não tiver idéia do que ele significa.', + 'cache_handler' => 'Manipulador de cache (cache handler)', + 'cacheHandlerOptions' => [ + 'file' => 'Arquivo', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Avançar', + 'submit' => 'Finalizar instalação', + 'create_superadmin' => 'Criar sua conta de superadmin', + 'email' => 'E-mail', + 'username' => 'Nome de usuário', + 'password' => 'Senha', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Sua conta superadmin foi criada com sucesso. Entre para começar a podcastar!', + 'databaseConnectError' => + 'O Castopod não pôde se conectar ao seu banco de dados. Edite sua configuração do banco de dados e tente novamente.', + 'writeError' => + "Não foi possível criar/escrever o arquivo `.env`. Você deve criá-lo manualmente, seguindo o template do arquivo `.env.example` no pacote Castopod.", + ], +]; diff --git a/modules/Admin/Language/pt-br/Navigation.php b/modules/Admin/Language/pt-br/Navigation.php new file mode 100644 index 00000000..a5032c7c --- /dev/null +++ b/modules/Admin/Language/pt-br/Navigation.php @@ -0,0 +1,44 @@ + 'Ativar/Desativar barra lateral', + 'go_to_website' => 'Ir para o site', + 'go_to_admin' => 'Ir para admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Painel de controle', + 'admin' => 'Início', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Todos os podcasts', + 'podcast-create' => 'Novo podcast', + 'all-podcast-imports' => 'Todos os importações de Podcast', + 'podcast-imports-add' => 'Importar um podcast', + 'persons' => 'Pessoas', + 'person-list' => 'Todas as pessoas', + 'person-create' => 'Nova pessoa', + 'fediverse' => 'Fediverso', + 'fediverse-blocked-actors' => 'Contas bloqueadas', + 'fediverse-blocked-domains' => 'Domínios bloqueados', + 'users' => 'Usuários', + 'user-list' => 'Todos os usuários', + 'user-create' => 'Novo usuário', + 'pages' => 'Páginas', + 'page-list' => 'Todas as páginas', + 'page-create' => 'Nova Página', + 'settings' => 'Confirgurações', + 'settings-general' => 'Geral', + 'settings-theme' => 'Tema', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'Minha conta', + 'change-password' => 'Alterar senha', + 'logout' => 'Desconectar', + ], +]; diff --git a/modules/Admin/Language/pt-br/Notifications.php b/modules/Admin/Language/pt-br/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/pt-br/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/pt-br/Page.php b/modules/Admin/Language/pt-br/Page.php new file mode 100644 index 00000000..772c73a7 --- /dev/null +++ b/modules/Admin/Language/pt-br/Page.php @@ -0,0 +1,30 @@ + 'Voltar ao Início', + 'page' => 'Página', + 'all_pages' => 'Todas as páginas', + 'create' => 'Nova página', + 'go_to_page' => 'Ir para a página', + 'edit' => 'Editar página', + 'delete' => 'Excluir página', + 'form' => [ + 'title' => 'Título', + 'permalink' => 'Link permanente', + 'content' => 'Conteúdo', + 'submit_create' => 'Criar página', + 'submit_edit' => 'Salvar', + ], + 'messages' => [ + 'createSuccess' => 'A página “{pageTitle}” foi criada com sucesso!', + 'editSuccess' => 'A página foi atualizada com sucesso!', + ], +]; diff --git a/modules/Admin/Language/pt-br/Pager.php b/modules/Admin/Language/pt-br/Pager.php new file mode 100644 index 00000000..2b39b6bb --- /dev/null +++ b/modules/Admin/Language/pt-br/Pager.php @@ -0,0 +1,21 @@ + 'Navegação da página', + 'first' => 'Primeira', + 'previous' => 'Anterior', + 'next' => 'Próxima', + 'last' => 'Última', + 'older' => 'Mais antiga', + 'newer' => 'Mais recente', + 'invalidTemplate' => '{0} não é um modelo de paginação válido.', + 'invalidPaginationGroup' => '{0} não é um grupo de paginação válido.', +]; diff --git a/modules/Admin/Language/pt-br/Person.php b/modules/Admin/Language/pt-br/Person.php new file mode 100644 index 00000000..293c37d2 --- /dev/null +++ b/modules/Admin/Language/pt-br/Person.php @@ -0,0 +1,65 @@ + 'Pessoas', + 'all_persons' => 'Todas as pessoas', + 'no_person' => 'Ninguém encontrado!', + 'create' => 'Criar uma pessoa', + 'view' => 'Visualizar pessoa', + 'edit' => 'Editar pessoa', + 'delete' => 'Excluir pessoa', + 'messages' => [ + 'createSuccess' => 'Pessoa criada com sucesso!', + 'editSuccess' => 'Pessoa foi atualizada com sucesso!', + 'deleteSuccess' => 'Pessoa foi removida!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar deve ser quadrado e ter pelo menos 400px de largura e altura.', + 'full_name' => 'Nome completo', + 'full_name_hint' => 'Este é o nome completo ou apelido da pessoa.', + 'unique_name' => 'Nome único', + 'unique_name_hint' => 'Utilizado para URLs', + 'information_url' => 'URL de informação', + 'information_url_hint' => + 'URL para um recurso relevante de informações sobre a pessoa, como uma página inicial ou uma plataforma de perfil de terceiros.', + 'submit_create' => 'Criar pessoa', + 'submit_edit' => 'Salvar pessoa', + ], + 'podcast_form' => [ + 'title' => 'Gerenciar pessoas', + 'add_section_title' => 'Adicionar pessoas a este podcast', + 'add_section_subtitle' => 'Você pode escolher várias pessoas e cargos.', + 'persons' => 'Pessoas', + 'persons_hint' => + 'Você pode selecionar uma ou várias pessoas com as mesmas funções. Você precisa primeiro criar as pessoas.', + 'roles' => 'Cargos', + 'roles_hint' => + 'Você pode selecionar nenhum, um ou vários cargos para uma pessoa.', + 'submit_add' => 'Adicionar pessoa(s)', + 'remove' => 'Remover', + ], + 'episode_form' => [ + 'title' => 'Gerenciar pessoas', + 'add_section_title' => 'Adicionar pessoas a este episódio', + 'add_section_subtitle' => 'Você pode escolher várias pessoas e cargos.', + 'persons' => 'Pessoas', + 'persons_hint' => + 'Você pode selecionar uma ou várias pessoas com os mesmos cargos. Você precisa primeiro criar as pessoas.', + 'roles' => 'Cargos', + 'roles_hint' => + 'Você pode selecionar nenhum, um ou vários cargos para uma pessoa.', + 'submit_add' => 'Adicionar pessoa(s)', + 'remove' => 'Remover', + ], + 'credits' => 'Créditos', +]; diff --git a/modules/Admin/Language/pt-br/Platforms.php b/modules/Admin/Language/pt-br/Platforms.php new file mode 100644 index 00000000..0388f65f --- /dev/null +++ b/modules/Admin/Language/pt-br/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Plataformas de podcasting', + 'social' => 'Redes sociais', + 'funding' => 'Links de financiamento', + ], + 'website' => 'Site', + 'home_url' => 'Ir para o site {platformName}', + 'register' => 'Registrar', + 'submit_url' => 'Enviar seu podcast para {platformName}', + 'your_link' => 'Seu link', + 'your_id' => [ + 'podcasting' => 'Seu ID', + 'social' => 'Seu ID', + 'funding' => 'Seu CTA', + ], + 'your_cta' => 'Sua chamada para ação', + 'visible' => 'Mostrar na página inicial do podcast?', + 'on_embed' => 'Mostrar no player incorporável?', + 'remove' => 'Remover {platformName}', + 'submit' => 'Salvar', + 'messages' => [ + 'updateSuccess' => 'Links foram atualizados com sucesso!', + 'removeLinkSuccess' => 'O link da plataforma foi removido.', + 'removeLinkError' => + 'O link da plataforma não pôde ser removido. Tente novamente.', + ], + 'description' => [ + 'podcasting' => 'O ID do podcast nesta plataforma', + 'social' => 'O ID da conta do podcast nesta plataforma', + 'funding' => 'Mensagem de chamada para ação', + ], +]; diff --git a/modules/Admin/Language/pt-br/Podcast.php b/modules/Admin/Language/pt-br/Podcast.php new file mode 100644 index 00000000..2d9e8708 --- /dev/null +++ b/modules/Admin/Language/pt-br/Podcast.php @@ -0,0 +1,330 @@ + 'Todos os podcasts', + 'no_podcast' => 'Nenhum podcast encontrado!', + 'create' => 'Criar podcast', + 'import' => 'Importar podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Novo Episódio', + 'view' => 'Ver podcast', + 'edit' => 'Editar podcast', + 'publish' => 'Publicar podcast', + 'publish_edit' => 'Editar publicação', + 'delete' => 'Excluir podcast', + 'see_episodes' => 'Ver episódios', + 'see_contributors' => 'Ver contribuidores', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Ir para a página', + 'latest_episodes' => 'Últimos episódios', + 'see_all_episodes' => 'Ver todos os episódios', + 'draft' => 'Rascunho', + 'messages' => [ + 'createSuccess' => 'Podcast criado com sucesso!', + 'editSuccess' => 'Podcast foi atualizado com sucesso!', + 'importSuccess' => 'Podcast foi importado com sucesso!', + 'deleteSuccess' => 'Podcast @{podcast_handle} excluído com sucesso!', + 'deletePodcastMediaError' => 'Falha ao excluir {type, select, + cover {a capa} + banner {o banner} + other {a mídia} + } do podcast.', + 'deleteEpisodeMediaError' => 'Falha ao excluir {type, select, + transcript {a transcrição} + chapters {os capítulos} + image {a capa} + audio {o áudio} + other {a mídia} + } do episódio de podcast {episode_slug}.', + 'deletePodcastMediaFolderError' => 'Falha ao excluir a pasta de mídia de podcast {folder_path}. Você pode removê-la manualmente de seu disco.', + 'podcastFeedUpdateSuccess' => 'Atualização bem sucedida: {number_of_new_episodes, plural, + one {# episódio foi adicionado} + other {# episódios foram adicionados} + } ao podcast!', + 'podcastFeedUpToDate' => 'O Podcast já está atualizado.', + 'publishError' => 'Este podcast já está publicado ou agendado para publicação.', + 'publishEditError' => 'Este podcast não está agendado para publicação.', + 'publishCancelSuccess' => 'Publicação do Podcast cancelada com sucesso!', + 'scheduleDateError' => 'Data de agendamento deve ser definida!', + ], + 'form' => [ + 'identity_section_title' => 'Identidade do podcast', + 'identity_section_subtitle' => 'Esses campos permitem que você seja notado.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Capa do podcast', + 'cover_size_hint' => 'A capa deve ser quadrada e ter pelo menos 1400px de largura e altura.', + 'banner' => 'Banner do podcast', + 'banner_size_hint' => 'Banner deve ter uma proporção 3:1 e ter ao menos 1500px de largura.', + 'banner_delete' => 'Excluir banner do podcast', + 'title' => 'Título', + 'handle' => 'Identificador', + 'handle_hint' => + 'Usado para identificar o podcast. Maiúsculas, minúsculas, números e underscores (_) são aceitos.', + 'type' => [ + 'label' => 'Tipo', + 'episodic' => 'Episódico', + 'episodic_hint' => 'Se os episódios são destinados a serem consumidos sem qualquer ordem específica. Os episódios mais recentes serão apresentados primeiro.', + 'serial' => 'Serial', + 'serial_hint' => 'Se a intenção é que os episódios sejam consumidos em uma ordem sequencial. Episódios vão ser apresentados em uma ordem numérica.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Descrição', + 'classification_section_title' => 'Classificação', + 'classification_section_subtitle' => + 'Esses campos terão impacto no seu público e na concorrência.', + 'language' => 'Idioma', + 'category' => 'Categoria', + 'category_placeholder' => 'Selecione uma categoria…', + 'other_categories' => 'Outras categorias', + 'parental_advisory' => [ + 'label' => 'Aviso aos pais', + 'hint' => 'Contém conteúdo explícito?', + 'undefined' => 'não definido', + 'clean' => 'Limpo', + 'explicit' => 'Explícito', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Quem está gerenciando o podcast?', + 'owner_name' => 'Nome do proprietário', + 'owner_name_hint' => + 'Apenas para uso administrativo. Visível no feed RSS público.', + 'owner_email' => 'E-mail do proprietário', + 'owner_email_hint' => + 'Será utilizado pela maioria das plataformas para verificar a propriedade do podcast. Visível no feed RSS público.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Editora', + 'publisher_hint' => + 'O grupo responsável pela criação do podcast. Muitas vezes se refere à empresa-mãe ou rede de um podcast. Este campo é por vezes rotulado como "Autor".', + 'copyright' => 'Direitos autorais', + 'location_section_title' => 'Localização', + 'location_section_subtitle' => 'Sobre que lugar é esse podcast?', + 'location_name' => 'Nome ou endereço da localização', + 'location_name_hint' => 'Este pode ser um lugar real ou fictício', + 'monetization_section_title' => 'Monetização', + 'monetization_section_subtitle' => + 'Ganhe dinheiro graças à sua audiência.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episódios devem ser definidos como premium por padrão', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Ativar serviço de análise OP3', + 'op3_enable_hint' => 'Por razões de segurança, os dados de análise dos episódios premium não serão compartilhados com o OP3.', + 'payment_pointer' => 'Endereço de pagamento (Payment Pointer) para web monetização', + 'payment_pointer_hint' => + 'Este é o seu lugar onde você receberá dinheiro graças à web monetização', + 'advanced_section_title' => 'Parâmetros Avançados', + 'advanced_section_subtitle' => + 'Se você precisa de tags RSS que Castopod não lida, defina-as aqui.', + 'custom_rss' => 'Tags RSS personalizadas para o podcast', + 'custom_rss_hint' => 'Isto será injetado dentro da tag ❬channel❭.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Nova URL de feed', + 'new_feed_url_hint' => 'Use este campo ao mover este podcast para outro domínio ou alterar hosts. Por padrão, este campo é preenchido com a URL do feed RSS atual se o podcast for importado.', + 'old_feed_url' => 'URL de feed antigo', + 'partnership' => 'Parceria', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL do link', + 'partner_image_url' => 'URL da imagem', + 'partner_id_hint' => 'Seu próprio ID de parceiro', + 'partner_link_url_hint' => 'O endereço genérico de link do parceiro', + 'partner_image_url_hint' => 'O endereço genérico da imagem de parceiro', + 'block' => 'O podcast deve ser ocultado dos catálogos públicos', + 'block_hint' => + 'O status do podcast: ativar isso impede que o podcast inteiro apareça em Apple Podcasts, Google Podcasts e qualquer aplicativo de terceiros que extraia programas desses diretórios. (Não garantido)', + 'complete' => 'Podcast não terá novos episódios', + 'lock' => 'Impedir que o podcast seja copiado', + 'lock_hint' => + 'O objetivo é dizer a outras plataformas de podcast se elas têm permissão para importar este feed. Um valor de "sim" significa que qualquer tentativa de importar esse feed para uma nova plataforma deve ser rejeitada.', + 'submit_create' => 'Criar podcast', + 'submit_edit' => 'Salvar podcast', + ], + 'category_options' => [ + 'uncategorized' => 'sem categoria', + 'arts' => 'Artes', + 'business' => 'Negócios', + 'comedy' => 'Comédia', + 'education' => 'Educação', + 'fiction' => 'Ficção', + 'government' => 'Governo', + 'health_and_fitness' => 'Saúde & Fitness', + 'history' => 'História', + 'kids_and_family' => 'Crianças & Família', + 'leisure' => 'Lazer', + 'music' => 'Música', + 'news' => 'Notícias', + 'religion_and_spirituality' => 'Religião e Espiritualidade', + 'science' => 'Ciência', + 'society_and_culture' => 'Sociedade e Cultura', + 'sports' => 'Esportes', + 'technology' => 'Tecnologia', + 'true_crime' => 'Crimes Verídicos', + 'tv_and_film' => 'TV & Filme', + 'books' => 'Livros', + 'design' => 'Design', + 'fashion_and_beauty' => 'Moda & Beleza', + 'food' => 'Culinária', + 'performing_arts' => 'Artes Cênicas', + 'visual_arts' => 'Artes Visuais', + 'careers' => 'Carreira', + 'entrepreneurship' => 'Empreendedorismo', + 'investing' => 'Investimento', + 'management' => 'Administração', + 'marketing' => 'Marketing', + 'non_profit' => 'Sem fins lucrativos', + 'comedy_interviews' => 'Entrevistas Cômicas', + 'improv' => 'Improvisação', + 'stand_up' => 'Stand-Up', + 'courses' => 'Cursos', + 'how_to' => 'Como fazer', + 'language_learning' => 'Aprendizagem de idiomas', + 'self_improvement' => 'Autoajuda', + 'comedy_fiction' => 'Ficção Cômica', + 'drama' => 'Drama', + 'science_fiction' => 'Ficção Científica', + 'alternative_health' => 'Saúde Alternativa', + 'fitness' => 'Fitness', + 'medicine' => 'Medicina', + 'mental_health' => 'Saúde Mental', + 'nutrition' => 'Nutrição', + 'sexuality' => 'Sexualidade', + 'education_for_kids' => 'Educação para Crianças', + 'parenting' => 'Maternidade/paternidade', + 'pets_and_animals' => 'Animais de estimação & Outros animais', + 'stories_for_kids' => 'Histórias para crianças', + 'animation_and_manga' => 'Animação & Mangá', + 'automotive' => 'Automotivo', + 'aviation' => 'Aviação', + 'crafts' => 'Artesanato', + 'games' => 'Jogos', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Casa & Jardim', + 'video_games' => 'Vídeo Games', + 'music_commentary' => 'Comentários sobre música', + 'music_history' => 'História da música', + 'music_interviews' => 'Entrevistas de Música', + 'business_news' => 'Notícias de Negócios', + 'daily_news' => 'Notícias Diárias', + 'entertainment_news' => 'Notícias de entretenimento', + 'news_commentary' => 'Comentários de Notícias', + 'politics' => 'Política', + 'sports_news' => 'Notícias Esportivas', + 'tech_news' => 'Notícias de Tecnologia', + 'buddhism' => 'Budismo', + 'christianity' => 'Cristianismo', + 'hinduism' => 'Hinduísmo', + 'islam' => 'Islã', + 'judaism' => 'Judaísmo', + 'religion' => 'Religião', + 'spirituality' => 'Espiritualidade', + 'astronomy' => 'Astronomia', + 'chemistry' => 'Química', + 'earth_sciences' => 'Ciências da Terra', + 'life_sciences' => 'Ciências da Vida', + 'mathematics' => 'Matemática', + 'natural_sciences' => 'Ciências Naturais', + 'nature' => 'Natureza', + 'physics' => 'Física', + 'social_sciences' => 'Ciências Sociais', + 'documentary' => 'Documentário', + 'personal_journals' => 'Diários', + 'philosophy' => 'Filosofia', + 'places_and_travel' => 'Lugares e Viagem', + 'relationships' => 'Relacionamentos', + 'baseball' => 'Beisebol', + 'basketball' => 'Basquete', + 'cricket' => 'Críquete', + 'fantasy_sports' => 'Esportes de Fantasia', + 'football' => 'Futebol Americano', + 'golf' => 'Golfe', + 'hockey' => 'Hóquei', + 'rugby' => 'Rúgbi', + 'running' => 'Corrida', + 'soccer' => 'Futebol', + 'swimming' => 'Natação', + 'tennis' => 'Tênis', + 'volleyball' => 'Voleibol', + 'wilderness' => 'Mundo Selvagem', + 'wrestling' => 'Luta Livre', + 'after_shows' => 'Nos Bastidores', + 'film_history' => 'História do Cinema', + 'film_interviews' => 'Entrevistas de Filmes', + 'film_reviews' => 'Avaliações de Filmes', + 'tv_reviews' => 'Avaliações de TV', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Voltar ao painel do podcast', + 'post' => 'Sua mensagem de publicação', + 'post_hint' => + "Escreva uma mensagem para anunciar a publicação do seu podcast. A mensagem será destacada na página inicial do seu podcast.", + 'message_placeholder' => 'Escreva a sua mensagem…', + 'submit' => 'Publicar', + 'publication_date' => 'Data de publicação', + 'publication_method' => [ + 'now' => 'Agora', + 'schedule' => 'Programar', + ], + 'scheduled_publication_date' => 'Data de publicação programada', + 'scheduled_publication_date_hint' => + 'Você pode agendar a liberação do podcast definindo uma data de publicação futura. Este campo deve ser formatado como YYYY-MM-DD HH:mm', + 'submit_edit' => 'Editar publicação', + 'cancel_publication' => 'Cancelar publicação', + 'message_warning' => 'Você não escreveu uma mensagem para o anúncio do episódio!', + 'message_warning_hint' => 'Ter uma mensagem aumenta o engajamento social, resultando em uma melhor visibilidade do seu podcast.', + 'message_warning_submit' => 'Publicar mesmo assim', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'modo rascunho', + 'not_published' => 'Este podcast ainda não foi publicado.', + 'scheduled' => 'Este podcast está programado para publicação em {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Excluir o podcast irá excluir todos os episódios, arquivos de mídia, publicações e estatísticas associados a ele. Essa ação é irreversível, você não será capaz de recuperá-la depois.", + 'understand' => 'Eu compreendo, quero que o podcast seja permanentemente excluído', + 'submit' => 'Excluir', + ], + 'by' => 'Por {publisher}', + 'season' => 'Temporada {seasonNumber}', + 'list_of_episodes_year' => 'Episódios de {year} ({episodeCount})', + 'list_of_episodes_season' => + 'Episódios da temporada {seasonNumber} ({episodeCount})', + 'no_episode' => 'Nenhum episódio encontrado!', + 'follow' => 'Seguir', + 'followers' => '{numberOfFollowers, plural, + one {# seguidor} + other {# seguidores} + }', + 'posts' => '{numberOfPosts, plural, + one {# publicação} + other {# publicações} + }', + 'activity' => 'Atividade', + 'episodes' => 'Episódios', + 'sponsor' => 'Apoiar', + 'funding_links' => 'Links de financiamento para {podcastTitle}', + 'find_on' => 'Encontrar {podcastTitle} em', + 'listen_on' => 'Ouvir em', +]; diff --git a/modules/Admin/Language/pt-br/PodcastNavigation.php b/modules/Admin/Language/pt-br/PodcastNavigation.php new file mode 100644 index 00000000..873954db --- /dev/null +++ b/modules/Admin/Language/pt-br/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Ir para página do podcast', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Painel do podcast', + 'podcast-view' => 'Início', + 'podcast-edit' => 'Editar podcast', + 'podcast-persons-manage' => 'Gerenciar pessoas', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episódios', + 'episode-list' => 'Todos os episódios', + 'episode-create' => 'Novo episódio', + 'analytics' => 'Estatísticas', + 'podcast-analytics' => 'Visão geral da audiência', + 'podcast-analytics-webpages' => 'Visitas às páginas web', + 'podcast-analytics-locations' => 'Localizações', + 'podcast-analytics-unique-listeners' => 'Ouvintes únicos', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Tempo de escuta', + 'podcast-analytics-time-periods' => 'Períodos de tempo', + 'monetization' => 'Monetization', + 'subscription-list' => 'Todas as assinaturas', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contribuidores', + 'contributor-list' => 'Todos os contribuidores', + 'contributor-add' => 'Adicionar contribuidor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Redes sociais', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/pt-br/Settings.php b/modules/Admin/Language/pt-br/Settings.php new file mode 100644 index 00000000..f326a094 --- /dev/null +++ b/modules/Admin/Language/pt-br/Settings.php @@ -0,0 +1,58 @@ + 'Configurações gerais', + 'instance' => [ + 'title' => 'Instância', + 'site_icon' => 'Ícone do site', + 'site_icon_delete' => 'Excluir ícone do site', + 'site_icon_hint' => 'Ícones de sites são o que você vê nas abas do seu navegador, barra de favoritos e quando você adiciona um site como um atalho em dispositivos móveis.', + 'site_icon_helper' => 'O ícone deve ser quadrado e ter pelo menos 512px de largura e altura.', + 'site_name' => 'Nome do site', + 'site_description' => 'Descrição do site', + 'submit' => 'Salvar', + 'editSuccess' => 'A instância foi atualizada com sucesso!', + 'deleteIconSuccess' => 'O ícone do site foi removido com sucesso!', + ], + 'images' => [ + 'title' => 'Imagens', + 'subtitle' => 'Aqui você pode regenerar todas as imagens baseadas nos originais que foram enviados. Para ser usado se você descobrir que algumas imagens estão faltando. Esta tarefa pode demorar um pouco.', + 'regenerate' => 'Regenerar imagens', + 'regenerationSuccess' => 'Todas as imagens foram regeneradas com sucesso!', + ], + 'housekeeping' => [ + 'title' => 'Manutenção', + 'subtitle' => 'Executa várias tarefas de manutenção. Use este recurso se você encontrar problemas com arquivos de mídia ou integridade de dados. Estas tarefas podem demorar um pouco.', + 'reset_counts' => 'Redefinir contadores', + 'reset_counts_helper' => 'Esta opção irá recalcular e redefinir todas as contagens de dados (número de seguidores, publicações, comentários, …).', + 'rewrite_media' => 'Reescrever metadados de mídia', + 'rewrite_media_helper' => 'Esta opção apagará todos os arquivos de mídia desnecessários e os recriará (imagens, arquivos de áudio, transcrições, capítulos, …)', + 'rename_episodes_files' => 'Renomear os arquivos de áudio de episódios', + 'rename_episodes_files_hint' => 'Esta opção irá renomear todos os episódios de arquivos de áudio para uma sequência aleatória de caracteres. Use isto se o link de seus episódios privados foi vazado, pois isso irá escondê-los efetivamente.', + 'clear_cache' => 'Limpar todo o cache', + 'clear_cache_helper' => 'Esta opção irá liberar o cache do redis ou arquivos graváveis/cache.', + 'run' => 'Executar manutenção', + 'runSuccess' => 'Manutenção foi realizada com sucesso!', + ], + 'theme' => [ + 'title' => 'Tema', + 'accent_section_title' => 'Cor de destaque', + 'accent_section_subtitle' => 'Escolha a cor para determinar a aparência de todas as páginas públicas.', + 'pine' => 'Pinheiro', + 'crimson' => 'Carmesim', + 'amber' => 'Âmbar', + 'lake' => 'Lago', + 'jacaranda' => 'Jacarandá', + 'onyx' => 'Ônix', + 'submit' => 'Salvar', + 'setInstanceThemeSuccess' => 'O tema foi atualizado com sucesso!', + ], +]; diff --git a/modules/Admin/Language/pt-br/Soundbite.php b/modules/Admin/Language/pt-br/Soundbite.php new file mode 100644 index 00000000..e91a4d5d --- /dev/null +++ b/modules/Admin/Language/pt-br/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Clipes de áudio', + 'soundbite' => 'Clipe de áudio', + ], + 'messages' => [ + 'createSuccess' => 'Clipe de áudio foi criado com sucesso!', + 'deleteSuccess' => 'Clipe de áudio foi removido com sucesso!', + ], + 'form' => [ + 'title' => 'Novo clipe de áudio', + 'soundbite_title' => 'Título do clipe de áudio', + 'start_time' => 'Começa em', + 'duration' => 'Duração', + 'submit' => 'Criar clipe de áudio', + ], + 'play' => 'Reproduzir o clipe de áudio', + 'stop' => 'Parar o clipe de áudio', + 'create' => 'Novo clipe de áudio', + 'delete' => 'Excluir o clipe de áudio', +]; diff --git a/modules/Admin/Language/pt-br/Validation.php b/modules/Admin/Language/pt-br/Validation.php new file mode 100644 index 00000000..1db87454 --- /dev/null +++ b/modules/Admin/Language/pt-br/Validation.php @@ -0,0 +1,17 @@ + + '{field} não é uma imagem ou não é largo ou alto o suficiente.', + 'is_image_ratio' => + '{field} não é uma imagem ou não tem a proporção correta.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/pt-br/VideoClip.php b/modules/Admin/Language/pt-br/VideoClip.php new file mode 100644 index 00000000..7c5095aa --- /dev/null +++ b/modules/Admin/Language/pt-br/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Clipes de vídeo', + 'status' => [ + 'label' => 'Status', + 'queued' => 'na fila', + 'queued_hint' => 'O clipe está esperando para ser processado.', + 'pending' => 'pendente', + 'pending_hint' => 'O clipe será gerado em breve.', + 'running' => 'executando', + 'running_hint' => 'O clipe está sendo gerado.', + 'failed' => 'falhou', + 'failed_hint' => 'O clipe não pode ser gerado: falha de script.', + 'passed' => 'aprovado', + 'passed_hint' => 'Clipe gerado com sucesso!', + ], + 'clip' => 'Clipe', + 'duration' => 'Duração da tarefa', + ], + 'title' => 'Clipe de vídeo: {videoClipLabel}', + 'download_clip' => 'Baixar clipe', + 'create' => 'Novo clipe de vídeo', + 'go_to_page' => 'Ir para a página do clipe', + 'retry' => 'Repetir a geração do clipe', + 'delete' => 'Excluir clipe', + 'logs' => 'Logs de tarefa', + 'messages' => [ + 'alreadyExistingError' => 'O clipe de vídeo que você está tentando criar já existe!', + 'addToQueueSuccess' => 'O clipe de vídeo foi adicionado à fila, aguardando ser criado!', + 'deleteSuccess' => 'O clipe de vídeo foi removido com sucesso!', + ], + 'format' => [ + 'landscape' => 'Paisagem', + 'portrait' => 'Retrato', + 'squared' => 'Quadrado', + ], + 'form' => [ + 'title' => 'Novo clipe de vídeo', + 'params_section_title' => 'Parâmetros do clipe de vídeo', + 'clip_title' => 'Título do clipe', + 'format' => [ + 'label' => 'Escolha um formato', + 'landscape_hint' => 'Com uma proporção de 16:9, os vídeos em paisagem são ótimos para PeerTube, Youtube e Vimeo.', + 'portrait_hint' => 'Com uma proporção de 9:16, os vídeos em retrato são ótimos para TikTok, Youtube shorts e Instagram stories.', + 'squared_hint' => 'Com uma proporção de 1:1, os vídeos quadrados são ótimos para Mastodon, Facebook, Twitter e LinkedIn.', + ], + 'theme' => 'Selecione um tema', + 'start_time' => 'Começa em', + 'duration' => 'Duração', + 'trim_start' => 'Início do corte', + 'trim_end' => 'Fim do corte', + 'submit' => 'Criar clipe de vídeo', + ], + 'requirements' => [ + 'title' => 'Requisitos ausentes', + 'missing' => 'Você tem requisitos ausentes. Certifique-se de adicionar todos os itens necessários para poder criar um vídeo para este episódio!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Biblioteca Freetype para GD', + 'transcript' => 'Arquivo de transcrição (.srt)', + ], +]; diff --git a/modules/Admin/Language/pt/AboutCastopod.php b/modules/Admin/Language/pt/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/pt/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/pt/Breadcrumb.php b/modules/Admin/Language/pt/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/pt/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/pt/Charts.php b/modules/Admin/Language/pt/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/pt/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/pt/Common.php b/modules/Admin/Language/pt/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/pt/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/pt/Countries.php b/modules/Admin/Language/pt/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/pt/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/pt/Dashboard.php b/modules/Admin/Language/pt/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/pt/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/pt/Episode.php b/modules/Admin/Language/pt/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/pt/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/pt/EpisodeNavigation.php b/modules/Admin/Language/pt/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/pt/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/pt/Fediverse.php b/modules/Admin/Language/pt/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/pt/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/pt/Home.php b/modules/Admin/Language/pt/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/pt/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/pt/Install.php b/modules/Admin/Language/pt/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/pt/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/pt/Navigation.php b/modules/Admin/Language/pt/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/pt/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/pt/Notifications.php b/modules/Admin/Language/pt/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/pt/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/pt/Page.php b/modules/Admin/Language/pt/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/pt/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/pt/Pager.php b/modules/Admin/Language/pt/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/pt/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/pt/Person.php b/modules/Admin/Language/pt/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/pt/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/pt/Platforms.php b/modules/Admin/Language/pt/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/pt/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/pt/Podcast.php b/modules/Admin/Language/pt/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/pt/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/pt/PodcastNavigation.php b/modules/Admin/Language/pt/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/pt/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/pt/Settings.php b/modules/Admin/Language/pt/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/pt/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/pt/Soundbite.php b/modules/Admin/Language/pt/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/pt/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/pt/Validation.php b/modules/Admin/Language/pt/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/pt/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/pt/VideoClip.php b/modules/Admin/Language/pt/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/pt/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/ro/AboutCastopod.php b/modules/Admin/Language/ro/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/ro/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/ro/Breadcrumb.php b/modules/Admin/Language/ro/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/ro/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/ro/Charts.php b/modules/Admin/Language/ro/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/ro/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/ro/Common.php b/modules/Admin/Language/ro/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/ro/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/ro/Countries.php b/modules/Admin/Language/ro/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/ro/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/ro/Dashboard.php b/modules/Admin/Language/ro/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/ro/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ro/Episode.php b/modules/Admin/Language/ro/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/ro/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ro/EpisodeNavigation.php b/modules/Admin/Language/ro/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/ro/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/ro/Fediverse.php b/modules/Admin/Language/ro/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/ro/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/ro/Home.php b/modules/Admin/Language/ro/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/ro/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/ro/Install.php b/modules/Admin/Language/ro/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/ro/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/ro/Navigation.php b/modules/Admin/Language/ro/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/ro/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/ro/Notifications.php b/modules/Admin/Language/ro/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/ro/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/ro/Page.php b/modules/Admin/Language/ro/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/ro/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/ro/Pager.php b/modules/Admin/Language/ro/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/ro/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/ro/Person.php b/modules/Admin/Language/ro/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/ro/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/ro/Platforms.php b/modules/Admin/Language/ro/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/ro/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/ro/Podcast.php b/modules/Admin/Language/ro/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/ro/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/ro/PodcastNavigation.php b/modules/Admin/Language/ro/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/ro/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ro/Settings.php b/modules/Admin/Language/ro/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/ro/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/ro/Soundbite.php b/modules/Admin/Language/ro/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/ro/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/ro/Validation.php b/modules/Admin/Language/ro/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/ro/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ro/VideoClip.php b/modules/Admin/Language/ro/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/ro/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/ru/AboutCastopod.php b/modules/Admin/Language/ru/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/ru/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/ru/Breadcrumb.php b/modules/Admin/Language/ru/Breadcrumb.php new file mode 100644 index 00000000..635a3806 --- /dev/null +++ b/modules/Admin/Language/ru/Breadcrumb.php @@ -0,0 +1,57 @@ + 'навигационная цепочка', + config('Admin') + ->gateway => 'Главная', + 'podcasts' => 'подкасты', + 'episodes' => 'выпуски', + 'subscriptions' => 'subscriptions', + 'contributors' => 'участников', + 'pages' => 'страниц', + 'settings' => 'настройки', + 'theme' => 'тема', + 'about' => 'about', + 'add' => 'добавить', + 'new' => 'новая', + 'edit' => 'изменить', + 'persons' => 'лица', + 'publish' => 'публикация', + 'publish-edit' => 'редактировать публикацию', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'снять с публикации', + 'delete' => 'удалить', + 'remove' => 'remove', + 'fediverse' => 'Федивёрс', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'пользователи', + 'my-account' => 'мой аккаунт', + 'change-password' => 'сменить пароль', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'платформы', + 'social' => 'социальные сети', + 'funding' => 'финансирование', + 'monetization-other' => 'other monetization', + 'analytics' => 'аналитика', + 'locations' => 'расположение', + 'webpages' => 'веб-страницы', + 'unique-listeners' => 'уникальные слушатели', + 'players' => 'проигрыватели', + 'listening-time' => 'время прослушивания', + 'time-periods' => 'период', + 'soundbites' => 'звуковые фрагменты', + 'video-clips' => 'видео клипы', + 'embed' => 'встроенный плеер', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/ru/Charts.php b/modules/Admin/Language/ru/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/ru/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/ru/Common.php b/modules/Admin/Language/ru/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/ru/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/ru/Countries.php b/modules/Admin/Language/ru/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/ru/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/ru/Dashboard.php b/modules/Admin/Language/ru/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/ru/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/ru/Episode.php b/modules/Admin/Language/ru/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/ru/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/ru/EpisodeNavigation.php b/modules/Admin/Language/ru/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/ru/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/ru/Fediverse.php b/modules/Admin/Language/ru/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/ru/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/ru/Home.php b/modules/Admin/Language/ru/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/ru/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/ru/Install.php b/modules/Admin/Language/ru/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/ru/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/ru/Navigation.php b/modules/Admin/Language/ru/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/ru/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/ru/Notifications.php b/modules/Admin/Language/ru/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/ru/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/ru/Page.php b/modules/Admin/Language/ru/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/ru/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/ru/Pager.php b/modules/Admin/Language/ru/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/ru/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/ru/Person.php b/modules/Admin/Language/ru/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/ru/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/ru/Platforms.php b/modules/Admin/Language/ru/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/ru/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/ru/Podcast.php b/modules/Admin/Language/ru/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/ru/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/ru/PodcastNavigation.php b/modules/Admin/Language/ru/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/ru/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/ru/Settings.php b/modules/Admin/Language/ru/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/ru/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/ru/Soundbite.php b/modules/Admin/Language/ru/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/ru/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/ru/Validation.php b/modules/Admin/Language/ru/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/ru/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/ru/VideoClip.php b/modules/Admin/Language/ru/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/ru/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/sk/AboutCastopod.php b/modules/Admin/Language/sk/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/sk/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/sk/Admin.php b/modules/Admin/Language/sk/Admin.php new file mode 100644 index 00000000..5e394237 --- /dev/null +++ b/modules/Admin/Language/sk/Admin.php @@ -0,0 +1,15 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'choose_interact' => 'Choose how to interact', +]; diff --git a/modules/Admin/Language/sk/Breadcrumb.php b/modules/Admin/Language/sk/Breadcrumb.php new file mode 100644 index 00000000..26cf0b17 --- /dev/null +++ b/modules/Admin/Language/sk/Breadcrumb.php @@ -0,0 +1,57 @@ + 'omrvinky', + config('Admin') + ->gateway => 'Úvod', + 'podcasts' => 'podcasty', + 'episodes' => 'časti', + 'subscriptions' => 'odbery', + 'contributors' => 'prispievatelia', + 'pages' => 'stránky', + 'settings' => 'nastavenia', + 'theme' => 'vzhľad', + 'about' => 'informácie', + 'add' => 'pridať', + 'new' => 'pridať', + 'edit' => 'upraviť', + 'persons' => 'osobnosti', + 'publish' => 'zverejniť', + 'publish-edit' => 'upraviť zverejnené', + 'publish-date-edit' => 'upraviť dátum publikovania', + 'unpublish' => 'zrušiť zverejnenie', + 'delete' => 'vymazať', + 'remove' => 'odstrániť', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'zablokovaní aktéri', + 'blocked-domains' => 'zablokované domény', + 'users' => 'používatelia', + 'my-account' => 'môj účet', + 'change-password' => 'zmeniť heslo', + 'imports' => 'nahratia', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platformy', + 'social' => 'sociálne siete', + 'funding' => 'financovanie', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytika', + 'locations' => 'miesta', + 'webpages' => 'web stránky', + 'unique-listeners' => 'unikátni poslucháči', + 'players' => 'prehrávače', + 'listening-time' => 'čas počúvania', + 'time-periods' => 'časové obdobia', + 'soundbites' => 'zvukové ukážky', + 'video-clips' => 'video klipy', + 'embed' => 'vnorený', + 'notifications' => 'oboznámenia', + 'suspend' => 'pozastaviť', +]; diff --git a/modules/Admin/Language/sk/Charts.php b/modules/Admin/Language/sk/Charts.php new file mode 100644 index 00000000..17c1187e --- /dev/null +++ b/modules/Admin/Language/sk/Charts.php @@ -0,0 +1,41 @@ + 'Prevzatia epizód podľa služby (za uplynulý týždeň)', + 'by_player_weekly' => 'Prevzatia epizód podľa prehrávača (za uplynulý týždeň)', + 'by_player_yearly' => 'Prevzatia epizód podľa prehrávača (za uplynulý rok)', + 'by_device_weekly' => 'Prevzatia epizód podľa zariadenia (za uplynulý týždeň)', + 'by_os_weekly' => 'Prevzatia epizód podľa operačného systému (za uplynulý týždeň)', + 'podcast_by_region' => 'Prevzatia epizód podľa regiónu (za uplynulý týždeň)', + 'unique_daily_listeners' => 'Denný unikátny počet poslucháčov', + 'unique_monthly_listeners' => 'Mesačný unikátny počet poslucháčov', + 'by_browser' => 'Používanie web stránok podľa prehliadača (za uplynulý týždeň)', + 'podcast_by_day' => 'Denné prevzatia epizód', + 'podcast_by_month' => 'Mesačné prevzatia epizód', + 'episode_by_day' => 'Denné prevzatia častí (prvých 60 dní)', + 'episode_by_month' => 'Mesačné prevzatia častí', + 'episodes_by_day' => + '5 posledných prevzatí častí (počas ich prvých 60 dní)', + 'by_country_weekly' => 'Prevzatia epizód podľa krajiny (za uplynulý týždeň)', + 'by_country_yearly' => 'Prevzatia epizód podľa krajiny (za uplynulý rok)', + 'by_domain_weekly' => 'Návštevy web stránok podľa zdroja (za uplynulý týždeň)', + 'by_domain_yearly' => 'Návštevy web stránok podľa zdroja (za uplynulý rok)', + 'by_entry_page' => 'Návštevy web stránok podľa prichádzajúcej stránky (za uplynulý týždeň)', + 'podcast_bots' => 'Roboti (crawlers)', + 'daily_listening_time' => 'Súhrnný denný čas počúvania', + 'monthly_listening_time' => 'Súhrnný mesačný čas počúvania', + 'by_weekday' => 'Podľa dní v týždni (za uplynulých 60 dní)', + 'by_hour' => 'Podľa denného času (Za uplynulých 60 dní)', + 'podcast_by_bandwidth' => 'Denný prenos údajov (v MB)', + 'total_storage_by_month' => 'Mesačné úložisko (v MB)', + 'total_bandwidth_by_month' => 'Mesačný prenos údajov (v MB)', + 'total_bandwidth_by_month_limit' => 'Obmedzený na {totalBandwidth} za mesiac', +]; diff --git a/modules/Admin/Language/sk/Common.php b/modules/Admin/Language/sk/Common.php new file mode 100644 index 00000000..584c05bf --- /dev/null +++ b/modules/Admin/Language/sk/Common.php @@ -0,0 +1,52 @@ + 'Áno', + 'no' => 'Nie', + 'cancel' => 'Zrušiť', + 'optional' => 'Nepovinné', + 'more' => 'Viac', + 'no_data' => 'Žiadne údaje!', + 'close' => 'Zavrieť', + 'edit' => 'Upraviť', + 'copy' => 'Kopírovať', + 'copied' => 'Skopírované!', + 'home' => 'Domov', + 'explicit' => 'Chúlostivé', + 'powered_by' => 'Poháňané cez {castopod}', + 'actions' => 'Akcie', + 'pageInfo' => 'Stránka {currentPage} z celkového počtu {pageCount}', + 'go_back' => 'Ísť späť', + 'forms' => [ + 'editor' => [ + 'write' => 'Písať', + 'preview' => 'Náhľad', + 'help' => 'Podporovaný markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Vyberte stlačením', + 'loadingText' => 'Načítanie…', + 'noResultsText' => 'Nenájdené žiadne výsledky', + 'noChoicesText' => 'Žiadne možnosti na výber', + 'maxItemText' => 'Nie je možné pridať viac položiek', + ], + 'upload_file' => 'Nahrať súbor', + 'remote_url' => 'Vzdialená adresa URL', + 'save' => 'Uložiť', + ], + 'play_episode_button' => [ + 'play' => 'Prehrať', + 'playing' => 'Prehrávané', + ], + 'size_limit' => 'Limit veľkosti: {0}.', + 'choose_interact' => 'Vyberte spôsob interakcie', + 'view' => 'Zobraziť', +]; diff --git a/modules/Admin/Language/sk/Countries.php b/modules/Admin/Language/sk/Countries.php new file mode 100644 index 00000000..8d5fa7cd --- /dev/null +++ b/modules/Admin/Language/sk/Countries.php @@ -0,0 +1,282 @@ + 'Andorra', + 'AE' => 'Spojené Arabské Emiráty', + 'AF' => 'Afganistan', + 'AG' => 'Antigua a Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albánsko', + 'AM' => 'Arménsko', + 'AO' => 'Angola', + 'AQ' => 'Antarktída', + 'AR' => 'Argentína', + 'AS' => 'Americká Samoa', + 'AT' => 'Rakúsko', + 'AU' => 'Austrália', + 'AW' => 'Aruba', + 'AX' => 'Ålandy', + 'AZ' => 'Azerbajdžan', + 'BA' => 'Bosna a Hercegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladéš', + 'BE' => 'Belgicko', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulharsko', + 'BH' => 'Bahrajn', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Svätý Bartolomej', + 'BM' => 'Bermudy', + 'BN' => 'Brunejsko-Darussalamsky Štát', + 'BO' => 'Bolívia, plurinský štát', + 'BQ' => 'Bonaire, Sint Eustatius a Sabaj', + 'BR' => 'Brazília', + 'BS' => 'Bahamy', + 'BT' => 'Bhután', + 'BV' => 'Bouvetov ostrov', + 'BW' => 'Botswana', + 'BY' => 'Bielorusko', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Kokosové ostrovy', + 'CD' => ' +Bhután +Bouvetov ostrov +Bielorusko +Kokosové ostrovy +Konžská demokratická republika', + 'CF' => 'Stredoafrická republika', + 'CG' => 'Kongo', + 'CH' => 'Švajčiarsko', + 'CI' => "Pobrežie slonoviny", + 'CK' => 'Cookove ostrovy', + 'CL' => 'Čile', + 'CM' => 'Kamerun', + 'CN' => 'Čína', + 'CO' => 'Kolumbia', + 'CR' => 'Kostarika', + 'CU' => 'Kuba', + 'CV' => 'Kapverdy', + 'CW' => 'Curaçao', + 'CX' => 'Vianočný Ostrov', + 'CY' => 'Cyprus', + 'CZ' => 'Česká republika', + 'DE' => 'Nemecko', + 'DJ' => 'Džibutsko', + 'DK' => 'Dánsko', + 'DM' => 'Dominika', + 'DO' => 'Dominikánska republika', + 'DZ' => 'Alžírsko', + 'EC' => 'Ekvádor', + 'EE' => 'Estónsko', + 'EG' => 'Egypt', + 'EH' => 'Západná Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Španielsko', + 'ET' => 'Etiópia', + 'FI' => 'Fínsko', + 'FJ' => 'Fidži', + 'FK' => 'Falklandské ostrovy (Malvíny)', + 'FM' => 'Mikronézia, federatívne štáty', + 'FO' => 'Faerské Ostrovy', + 'FR' => 'Francúzsko', + 'GA' => 'Gabon', + 'GB' => 'Spojené Kráľovstvo', + 'GD' => 'Grenada', + 'GE' => 'Gruzínsko', + 'GF' => 'Francúzska Guayana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltár', + 'GL' => 'Grónsko', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Rovníková Guinea', + 'GR' => 'Grécko', + 'GS' => 'Južná Georgia a Južné Sandwichove ostrovy', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Teritórium Heardovho ostrova a Macdonaldových ostrovov', + 'HN' => 'Honduras', + 'HR' => 'Chorvátsko', + 'HT' => 'Haiti', + 'HU' => 'Maďarsko', + 'ID' => 'Indonézia', + 'IE' => 'Írsko', + 'IL' => 'Izrael', + 'IM' => 'Ostrov Man', + 'IN' => 'India', + 'IO' => 'Britské indickooceánske územie', + 'IQ' => 'Irak', + 'IR' => 'Irán, Islamská republika', + 'IS' => 'Island', + 'IT' => 'Taliansko', + 'JE' => 'Jersey', + 'JM' => 'Jamajka', + 'JO' => 'Jordánsko', + 'JP' => 'Japonsko', + 'KE' => 'Keňa', + 'KG' => 'Kirgizsko', + 'KH' => 'Kambodža', + 'KI' => 'Kiribati', + 'KM' => 'Komory', + 'KN' => 'Svätý Krištof a Nevis', + 'KP' => "Kórea, Demokratická ľudová republika", + 'KR' => 'Kórejská Republika', + 'KW' => 'Kuvajt', + 'KY' => 'Kajmanské ostrovy', + 'KZ' => 'Kazachstan', + 'LA' => "_03 slovutny poprad. mp3 +Kapverdy +Dominika +Mikronézia, federatívne štáty +Francúzska Guayana +Rovníková Guinea +Komory +Svätý Krištof a Nevis +Kórea, Demokratická ľudová republika +Kórejská Republika +Kuvajt +Kajmanské ostrovy +Kazachstan +Laoská ľudovodemokratická Republika", + 'LB' => 'Libanon', + 'LC' => 'Svätá Lucia', + 'LI' => 'Lichtenštajnsko', + 'LK' => 'Srí Lanka', + 'LR' => 'Libéria', + 'LS' => 'Lesotho', + 'LT' => 'Litva', + 'LU' => 'Luxembursko', + 'LV' => 'Lotyšsko', + 'LY' => 'Líbia', + 'MA' => 'Maroko', + 'MC' => 'Monako', + 'MD' => 'Moldavská Republika', + 'ME' => 'Čierna Hora', + 'MF' => 'Svätý Martin (Francúzska časť)', + 'MG' => 'Madagaskar', + 'MH' => 'Marshallove ostrovy', + 'MK' => 'Macedónsko-Bývalá Juhoslovanská Republika', + 'ML' => 'Mali', + 'MM' => 'Mjanmarsko', + 'MN' => 'Mongolsko', + 'MO' => 'Macao', + 'MP' => 'Severné Mariány', + 'MQ' => 'Martinik', + 'MR' => 'Mauritánia', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Maurícius', + 'MV' => 'Maledivy', + 'MW' => 'Malawi', + 'MX' => 'Mexiko', + 'MY' => 'Malajzia', + 'MZ' => 'Mozambik', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namíbia', + 'NC' => 'Nová Kaledónia', + 'NE' => 'Niger', + 'NF' => 'Ostrov Norfolk', + 'NG' => 'Nigéria', + 'NI' => 'Nikaragua', + 'NL' => 'Holandsko', + 'NO' => 'Nórsko', + 'NP' => 'Nepál', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nový Zéland', + 'OM' => 'Omán', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Francúzska Polynézia', + 'PG' => 'Papua-Nová Guinea', + 'PH' => 'Filipíny', + 'PK' => 'Pakistan', + 'PL' => 'Poľsko', + 'PM' => 'Svätý Peter a Michal', + 'PN' => 'Pitcairnove ostrovy', + 'PR' => 'Portoriko', + 'PS' => 'Palestínske okupované územia', + 'PT' => 'Portugalsko', + 'PW' => 'Palau', + 'PY' => 'Paraguaj', + 'QA' => 'Katar', + 'RE' => 'Réunion', + 'RO' => 'Rumunsko', + 'RS' => 'Srbsko', + 'RU' => 'Ruská Federácia', + 'RW' => 'Rwanda', + 'SA' => 'Saudská Arábia', + 'SB' => 'Šalamúnove ostrovy', + 'SC' => 'Seychely', + 'SD' => 'Sudán', + 'SE' => 'Švédsko', + 'SG' => 'Singapur', + 'SH' => 'Svätá Helena, Ascension a Tristan da Cunha', + 'SI' => 'Slovinsko', + 'SJ' => 'Špicbergy a Jan Mayen', + 'SK' => 'Slovensko', + 'SL' => 'Sierra Leone', + 'SM' => 'San Maríno', + 'SN' => 'Senegal', + 'SO' => 'Somálsko', + 'SR' => 'Surinam', + 'SS' => 'Južný Sudán', + 'ST' => 'Svätý Tomáš a Principov ostrov', + 'SV' => 'Salvádor', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Sýrska Arabská Republika', + 'SZ' => 'Svazijsko', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Čad', + 'TF' => 'Francúzske južné územia', + 'TG' => 'Togo', + 'TH' => 'Thajsko', + 'TJ' => 'Tadžikistan', + 'TK' => 'Tokelau', + 'TL' => 'Východný Timor', + 'TM' => 'Turkménsko', + 'TN' => 'Tunisko', + 'TO' => 'Tonga', + 'TR' => 'Turecko', + 'TT' => 'Trinidad a Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, provincia Číny', + 'TZ' => 'Tanzánia', + 'UA' => 'Ukraina', + 'UG' => 'Uganda', + 'UM' => 'Menšie Odľahlé Ostrovy Spojených Štátov', + 'US' => 'Spojené Štáty', + 'UY' => 'Uruguaj', + 'UZ' => 'Uzbekistán', + 'VA' => 'Svätá Stolica (Vatikánsky Mestský Štát)', + 'VC' => 'Svätý Vincent a Grenadíny', + 'VE' => 'Venezuela, Bolívarovská republika', + 'VG' => 'Britské Panenské ostrovy', + 'VI' => 'Americké Panenské ostrovy', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis a Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Mayotte', + 'ZA' => 'Južná Afrika', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/sk/Dashboard.php b/modules/Admin/Language/sk/Dashboard.php new file mode 100644 index 00000000..aaa4ba40 --- /dev/null +++ b/modules/Admin/Language/sk/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Časti', + 'not_found' => 'Žiadna zverejnená časť', + 'last_published' => 'Naposledy zverejnené dňa {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/sk/Episode.php b/modules/Admin/Language/sk/Episode.php new file mode 100644 index 00000000..ac561290 --- /dev/null +++ b/modules/Admin/Language/sk/Episode.php @@ -0,0 +1,229 @@ + 'Séria {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Epizóda {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Séria {seasonNumber} epizóda {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# komentár} + few {# komentáre} + many {# komentárov} + other {# komentárov} + }', + 'all_podcast_episodes' => 'Všetky epizódy podcastu', + 'back_to_podcast' => 'Späť na podcast', + 'edit' => 'Upraviť', + 'preview' => 'Náhľad', + 'publish' => 'Zverejniť', + 'publish_edit' => 'Upraviť zverejnenie', + 'publish_date_edit' => 'Upraviť dátum zverejnenia', + 'unpublish' => 'Zrušiť zverejnenie', + 'publish_error' => 'Epizóda je už zverejnená.', + 'publish_edit_error' => 'Epizóda je už zverejnená.', + 'publish_cancel_error' => 'Epizóda je už zverejnená.', + 'publish_date_edit_error' => 'Epizóda zatiaľ nie je zverejnená, nie je možné upraviť dátum zverejnenia.', + 'publish_date_edit_future_error' => 'Dátum zverejnenia musí byť v minulosti! Ak si zverejnenie želáte naplánovať v budúcnosti, musíte ho najskôr zrušiť.', + 'publish_date_edit_success' => 'Dátum zverejnenia epizódy bol úspešne aktualizovaný!', + 'unpublish_error' => 'Epizóda nie je zverejnená.', + 'delete' => 'Vymazať', + 'go_to_page' => 'Prejsť na stránku', + 'create' => 'Pridať epizódu', + 'publication_status' => [ + 'published' => 'Zverejnená', + 'with_podcast' => 'Zverejnený', + 'scheduled' => 'Naplánovaná', + 'not_published' => 'Nezverejnená', + ], + 'with_podcast_hint' => 'Bude publikovaná v rovnakom čase ako podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Vyhľadať epizódu', + 'clear' => 'Vyčistiť hľadanie', + 'submit' => 'Hľadať', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# epizóda} + few {# epizódy} + many {# epizód} + other {# epizód} + }', + 'episode' => 'Epizóda', + 'visibility' => 'Viditeľnosť', + 'downloads' => 'Stiahnutia', + 'comments' => 'Komentáre', + 'actions' => 'Úkony', + ], + 'messages' => [ + 'createSuccess' => 'Epizóda je úspešne vytvorená!', + 'editSuccess' => 'Epizóda je úspešne aktualizovaná!', + 'publishSuccess' => '{publication_status, select, + published {Epizóda je úspešne zverejnená!} + scheduled {Zverejnenie epizódy je úspešne načasované!} + with_podcast {Táto epizóda bude zverejnená v rovnakom čase ako podcast.} + other {Táto epizóda nie je zverejnená.} + }', + 'publishCancelSuccess' => 'Zverejnenie epizódy úspešne zrušené!', + 'unpublishBeforeDeleteTip' => 'Pred vymazaním musíte zrušiť zverejnenie epizódy.', + 'scheduleDateError' => 'Musí byť nastavený plánovaný dátum zverejnenia!', + 'deletePublishedEpisodeError' => 'Prosím zrušte zverejnenie epizódy pred jej vymazaním.', + 'deleteSuccess' => 'Epizóda úspešne vymazaná!', + 'deleteError' => 'Nepodarilo sa vymazať epizódu: {type, select, + transcript {prepis} + chapters {kapitoly} + image {obrázok} + audio {zvuk} + other {médiá} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Epizóda s takýmto trvalým odkazom už existuje.', + ], + 'form' => [ + 'file_size_error' => + 'Súbor je príliš veľký! Maximálna povolená veľkosť je {0}. V konfigurácii Php zvýšte hodnoty nastavení `memory_limit`, `upload_max_filesize` a `post_max_size` a následne reštartujte web server, aby ste súbor mohli nahrať znovu.', + 'audio_file' => 'Zvukový súbor', + 'audio_file_hint' => 'Vyberte zvukový súbor .mp3, alebo .m4a.', + 'info_section_title' => 'Informácie o časti', + 'cover' => 'Obal k časti', + 'cover_hint' => + 'Ak obrázok nepridáte, použije sa obrázok podcastu.', + 'cover_size_hint' => 'Obrázok musí byť štvorcový minimálny rozmer 1400px.', + 'title' => 'Názov', + 'title_hint' => + 'Má obsahovať jasný a výstižný názov. Nepridávajte čísla sérií a epizód.', + 'permalink' => 'Trvalý odkaz', + 'season_number' => 'Séria', + 'episode_number' => 'Epizóda', + 'type' => [ + 'label' => 'Typ', + 'full' => 'Celá epizóda', + 'full_hint' => '´Uplný obsah', + 'trailer' => 'Upútavka', + 'trailer_hint' => 'Krátky promočný úryvok obsahu, ktorý slúži ako ukážka podcastu', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Doplnkový obsah podcastu (Informácie zo zákulisia alebo rozhovor s účinkujúcimi) alebo upútavka iného podcastu', + ], + 'premium_title' => 'Prémiový obsah', + 'premium' => 'Epizóda je prístupná len pre predplatiteľov prémiového obsahu', + 'parental_advisory' => [ + 'label' => 'Rodičovská kontrola', + 'hint' => 'Obsahuje epizóda explicitný obsah?', + 'undefined' => 'neuvedené', + 'clean' => 'Čisté', + 'explicit' => 'Chúlostivé', + ], + 'show_notes_section_title' => 'Poznámky epizódy', + 'show_notes_section_subtitle' => + 'Maximálne 4000 znakov, buďte jasní a výstižní.', + 'description' => 'Popis', + 'description_footer' => 'Päta popisu', + 'description_footer_hint' => + 'Tento text je pridaný na koniec popisu každej epizódy, je vhodný napríklad na zverejnenie odkazov na sociálne siete.', + 'additional_files_section_title' => 'Dodatočné súbory', + 'additional_files_section_subtitle' => + 'Tieto súbory sú určené na použitie s inými platformami s cieľom poslucháčom poskytovať bohačšiu skúsenosť. Pre viac informácií si pozrite {podcastNamespaceLink}.', + 'location_section_title' => 'Lokácia', + 'location_section_subtitle' => 'O akom mieste / oblasti pojednáva táto epizóda?', + 'location_name' => 'Názov oblasti alebo adresa', + 'location_name_hint' => 'Môže to byť skutočné alebo vymyslené miesto', + 'transcript' => 'Prepis (titulky / skryté titulky)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Stiahnuť prepis', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Vzdialená adresa Url s prepisom', + 'transcript_file_delete' => 'Vymazať súbor s prepisom', + 'chapters' => 'Kapitoly', + 'chapters_hint' => 'Súbor musí byť vo formáte JSON Chapters.', + 'chapters_download' => 'Prevziať kapitoly', + 'chapters_file' => 'Súbor s kapitolami', + 'chapters_remote_url' => 'Vzdialená adresa url súboru s kapitolami', + 'chapters_file_delete' => 'Vymazať súbor s kapitolami', + 'advanced_section_title' => 'Pokročilé vlastnosti', + 'advanced_section_subtitle' => + 'Ak potrebujete pokročilé tagy RSS, ktoré castopod nepodporuje, nastavte ich tu.', + 'custom_rss' => 'Vlastné tagy RSS pre túto epizódu', + 'custom_rss_hint' => 'Toto bude vložené vo vnútri tagu ❬item❭.', + 'block' => 'Epizóda má byť skrytá z verejných katalógov', + 'block_hint' => + 'Stav skryť / zobraziť pre túto epizódu: zapnutím zabránite, aby sa epizóda zobrazila v katalógoch Apple Podcasts, Google Podcasts a v ďalších aplikáciách tretích strán ktoré získavajú podcasty z týchto služieb. (Negarantované)', + 'submit_create' => 'Vytvoriť epizódu', + 'submit_edit' => 'Uložiť epizódu', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Späť na nástenku epizódy', + 'post' => 'Príspevok, ktorým oznamujete zverejnenie', + 'post_hint' => + "Napíšte správu, v ktorej oznámite zverejnenie tejto epizódy. Správu uvidia všetci sledujúci vo fediverse a správa bude zobrazená na úvodnej stránke podcastu.", + 'message_placeholder' => 'Napíšte správu…', + 'publication_date' => 'Dátum zverejnenia', + 'publication_method' => [ + 'now' => 'Hneď teraz', + 'schedule' => 'Naplánovať', + 'with_podcast' => 'Publikovať spolu s podcastom', + ], + 'scheduled_publication_date' => 'Dátum plánovaného zverejnenia', + 'scheduled_publication_date_clear' => 'Vyčistiť dátum zverejnenia', + 'scheduled_publication_date_hint' => + 'Uvedenie epizódy môžete naplánovať nastavením dátumu zverejnenia v budúcnosti. Formát tohoto vstupného poľa je YYYY-MM-DD HH:mm', + 'submit' => 'Zverejniť', + 'submit_edit' => 'Upraviť zverejnenie', + 'cancel_publication' => 'Zrušiť zverejnenie', + 'message_warning' => 'Nenapísali ste text oznamujúceho príspevku!', + 'message_warning_hint' => 'Odoslaním uvádzacieho príspevku zlepšujete sociálnu účasť, čím môžete ešte viac zviditeľniť váš podcast.', + 'message_warning_submit' => 'Napriek tomu zverejniť', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nový dátum zverejnenia', + 'new_publication_date_hint' => 'Musí byť dátum v minulosti.', + 'submit' => 'Upraviť dátum zverejnenia', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Zrušenie zverejnenia odstráni všetky pridružené príspevky a komentáre a odstráni epizódu z kanála RSS.", + 'understand' => 'Rozumiem, chcem zrušiť zverejnenie epizódy', + 'submit' => 'Zrušiť zverejnenie', + ], + 'delete_form' => [ + 'disclaimer' => + "Vymazaním epizódy odstránite všetky prepojené mediálne súbory, komentáre, video klipy a zvukové ukážky.", + 'understand' => 'Rozumiem, chcem vymazať epizódu', + 'submit' => 'Vymazať', + ], + 'embed' => [ + 'title' => 'Vnorený prehrávač', + 'label' => + 'Vyberte farbu vzhľadu, skopírujte kód prehrávača do schránky a prilepte ho na vašej stránke.', + 'clipboard_iframe' => 'Skopírovať kód prehrávača do schránky', + 'clipboard_url' => 'Skopírovať adresu do schránky', + 'dark' => 'Tmavý', + 'dark-transparent' => 'Tmavý priehľadný', + 'light' => 'Svetlý', + 'light-transparent' => 'Svetlý priehľadný', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'konceptový režim', + 'text' => '{publication_status, select, + published {Táto epizóda ešte nieje zverejnená.} + scheduled {Táto epizóda je naplánovaná na zverejnenie {publication_date}.} + with_podcast {Táto epizóda bude zverejnená zarovno s podcastom.} + other {Táto epizóda ešte nieje zverejnená.} + }', + 'preview' => 'Náhľad', + ], +]; diff --git a/modules/Admin/Language/sk/EpisodeNavigation.php b/modules/Admin/Language/sk/EpisodeNavigation.php new file mode 100644 index 00000000..8414aebe --- /dev/null +++ b/modules/Admin/Language/sk/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Zobraziť stránku časti', + 'dashboard' => 'Nástenka epizódy', + 'episode-view' => 'Domov', + 'episode-edit' => 'Upraviť časť', + 'episode-persons-manage' => 'Spravovať osobnosti', + 'embed-add' => 'Vnorený prehrávač', + 'clips' => 'Klipy', + 'video-clips-list' => 'Video klipy', + 'video-clips-create' => 'Nový video klip', + 'soundbites-list' => 'Zvukové ukážky', + 'soundbites-create' => 'Nová zvučka', +]; diff --git a/modules/Admin/Language/sk/Fediverse.php b/modules/Admin/Language/sk/Fediverse.php new file mode 100644 index 00000000..69cf2fb5 --- /dev/null +++ b/modules/Admin/Language/sk/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Účet nieje možné nájsť!', + 'blockActorSuccess' => '{actor} bol/i zablokovaný!', + 'unblockActorSuccess' => 'Aktér bol odblokovaný!', + 'blockDomainSuccess' => '{domain} bola zablokovaná!', + 'unblockDomainSuccess' => '{domain} bola odblokovaná!', + ], + 'blocked_actors' => 'Blokované účty', + 'blocked_domains' => 'Zablokované domény', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Názov domény', + 'submit' => 'Blokovať!', + ], + 'list' => [ + 'actor' => 'Účet', + 'domain' => 'Názov domény', + 'unblock' => 'Odblokovať', + ], +]; diff --git a/modules/Admin/Language/sk/Home.php b/modules/Admin/Language/sk/Home.php new file mode 100644 index 00000000..942992fd --- /dev/null +++ b/modules/Admin/Language/sk/Home.php @@ -0,0 +1,14 @@ + 'Všetky podcasty', + 'no_podcast' => 'Žiadne podcasty nenájdené', +]; diff --git a/modules/Admin/Language/sk/Install.php b/modules/Admin/Language/sk/Install.php new file mode 100644 index 00000000..c9669cdf --- /dev/null +++ b/modules/Admin/Language/sk/Install.php @@ -0,0 +1,61 @@ + 'Vlastnoručné nastavenie', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Nastavenie inštancie', + 'hostname' => 'Názov hostiteľa', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Nastavenie databázy', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Server databázy', + 'db_name' => 'Názov databázy', + 'db_username' => 'Prihlasovacie meno do databázy', + 'db_password' => 'Heslo databázy', + 'db_prefix' => 'Prefix databázy', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Nastavenie cache', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Obslužný mechanizmus vyrovnávacej pamäte', + 'cacheHandlerOptions' => [ + 'file' => 'Súbor', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Ďalej', + 'submit' => 'Dokončiť inštaláciu', + 'create_superadmin' => 'Vytvoriť účet hlavného správcu', + 'email' => 'Email', + 'username' => 'Meno používateľa', + 'password' => 'Heslo', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Účet hlavného správcu je úspešne vytvorený. Prihláste sa a začnite podcastovať!', + 'databaseConnectError' => + 'Castopod sa nedokáže pripojiť k databáze. Upravte konfiguráciu a skúste znovu.', + 'writeError' => + "Nie je možné vytvoriť/zapísať súbor `.env`. Mali by ste ho vytvoriť ručne podľa vzoru v súbore `.env.example` v balíku castopod.", + ], +]; diff --git a/modules/Admin/Language/sk/Navigation.php b/modules/Admin/Language/sk/Navigation.php new file mode 100644 index 00000000..2183aec0 --- /dev/null +++ b/modules/Admin/Language/sk/Navigation.php @@ -0,0 +1,44 @@ + 'Prepnúť postranný panel', + 'go_to_website' => 'Prejsť na webstránku', + 'go_to_admin' => 'Spravovať', + 'not-authorized' => 'Neautorizovaný', + 'dashboard' => 'Nástenka', + 'admin' => 'Úvod', + 'podcasts' => 'Podcasty', + 'podcast-list' => 'Všetky podcasty', + 'podcast-create' => 'Nový podcast', + 'all-podcast-imports' => 'Všetky nahrané podcasty', + 'podcast-imports-add' => 'Importovať podcast', + 'persons' => 'Osobnosti', + 'person-list' => 'Všetky osobnosti', + 'person-create' => 'Nová osobnosť', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blokované účty', + 'fediverse-blocked-domains' => 'Blokované domény', + 'users' => 'Používatelia', + 'user-list' => 'Všetci používatelia', + 'user-create' => 'Nový používateľ', + 'pages' => 'Stránky', + 'page-list' => 'Všetky stránky', + 'page-create' => 'Nová stránka', + 'settings' => 'Nastavenia', + 'settings-general' => 'Všeobecné', + 'settings-theme' => 'Vzhľad', + 'admin-about' => 'O aplikácii', + 'account' => [ + 'my-account' => 'Môj účet', + 'change-password' => 'Zmeniť heslo', + 'logout' => 'Odhlásiť sa', + ], +]; diff --git a/modules/Admin/Language/sk/Notifications.php b/modules/Admin/Language/sk/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/sk/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/sk/Page.php b/modules/Admin/Language/sk/Page.php new file mode 100644 index 00000000..9b2fa2e6 --- /dev/null +++ b/modules/Admin/Language/sk/Page.php @@ -0,0 +1,30 @@ + 'Späť na úvod', + 'page' => 'Stránka', + 'all_pages' => 'Všetky stránky', + 'create' => 'Nová stránka', + 'go_to_page' => 'Prejsť na stránku', + 'edit' => 'Upraviť stránku', + 'delete' => 'Vymazať stránku', + 'form' => [ + 'title' => 'Názov', + 'permalink' => 'Trvalý odkaz', + 'content' => 'Obsah', + 'submit_create' => 'Vytvoriť stránku', + 'submit_edit' => 'Uložiť', + ], + 'messages' => [ + 'createSuccess' => 'Stránka “{pageTitle}” bola úspešne vytvorená!', + 'editSuccess' => 'Stránka bola úspešne aktualizovaná!', + ], +]; diff --git a/modules/Admin/Language/sk/Pager.php b/modules/Admin/Language/sk/Pager.php new file mode 100644 index 00000000..43b98de4 --- /dev/null +++ b/modules/Admin/Language/sk/Pager.php @@ -0,0 +1,21 @@ + 'Navigácia stránky', + 'first' => 'Prvá', + 'previous' => 'Predošlá', + 'next' => 'Ďalšia', + 'last' => 'Posledná', + 'older' => 'Staršia', + 'newer' => 'Novšia', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/sk/Person.php b/modules/Admin/Language/sk/Person.php new file mode 100644 index 00000000..9c523798 --- /dev/null +++ b/modules/Admin/Language/sk/Person.php @@ -0,0 +1,65 @@ + 'Osobnosti', + 'all_persons' => 'Všetky osobnosti', + 'no_person' => 'Nikto nenájdený!', + 'create' => 'Vytvoriť osobnosť', + 'view' => 'Ukázať osobnosť', + 'edit' => 'Upraviť osobnosť', + 'delete' => 'Vymazať osobnosť', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Osobnosť bol/a odstránená!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Obrázok musí byť štvorcový a minimálne 400px široký a vysoký.', + 'full_name' => 'Celé meno', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unikátne meno', + 'unique_name_hint' => 'Použité pre URL odkazy', + 'information_url' => 'Informačná URL adresa', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Vytvoriť osobnosť', + 'submit_edit' => 'Uložiť osobnosť', + ], + 'podcast_form' => [ + 'title' => 'Spravovať osobnosti', + 'add_section_title' => 'Pridať osobnosti k tomuto podcastu', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Osobnosti', + 'persons_hint' => + 'Môžete vybrať jednu, alebo viac osôb s tou istou rolou. Najprv musíte osobnosti vytvoriť.', + 'roles' => 'Úlohy', + 'roles_hint' => + 'Pre osobu môžete vybrať žiadnu, jednu, alebo viac rolí.', + 'submit_add' => 'Pridať osob(y)', + 'remove' => 'Odstrániť', + ], + 'episode_form' => [ + 'title' => 'Spravovať osobnosti', + 'add_section_title' => 'Pridať osobnosti k tejto epizóde', + 'add_section_subtitle' => 'Môžete vybrať viacero osôb a rolí.', + 'persons' => 'Osobnosti', + 'persons_hint' => + 'Môžete vybrať jednu alebo viac osôb s tou istou rolou. Najprv by ste mali osobnosti vytvoriť.', + 'roles' => 'Roly', + 'roles_hint' => + 'Pre jednu osobu môžete vybrať žiadnu, jednu alebo viac rolí.', + 'submit_add' => 'Pridať osob(y)', + 'remove' => 'Odstrániť', + ], + 'credits' => 'Zásluhy', +]; diff --git a/modules/Admin/Language/sk/Platforms.php b/modules/Admin/Language/sk/Platforms.php new file mode 100644 index 00000000..cc0bd289 --- /dev/null +++ b/modules/Admin/Language/sk/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcastové platformy', + 'social' => 'Sociálne siete', + 'funding' => 'Funding links', + ], + 'website' => 'Webová stránka', + 'home_url' => 'Prejsť na stránku {platformName}', + 'register' => 'Registrovať', + 'submit_url' => 'Uverejniť podcast na platforme {platformName}', + 'your_link' => 'Váš odkaz', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Zobraziť na úvodnej stránke podcastu?', + 'on_embed' => 'Zobraziť na vnorenom prehrávači?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Uložiť', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/sk/Podcast.php b/modules/Admin/Language/sk/Podcast.php new file mode 100644 index 00000000..9e630c09 --- /dev/null +++ b/modules/Admin/Language/sk/Podcast.php @@ -0,0 +1,330 @@ + 'Všetky podcasty', + 'no_podcast' => 'Žiadny podcast nenájdený!', + 'create' => 'Vytvoriť podcast', + 'import' => 'Importovať podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Nová časť', + 'view' => 'Zobraziť podcast', + 'edit' => 'Upraviť podcast', + 'publish' => 'Zverejniť podcast', + 'publish_edit' => 'Upraviť zverejnené', + 'delete' => 'Vymazať podcast', + 'see_episodes' => 'Ukázať časti', + 'see_contributors' => 'Pozrieť prispievateľov', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Prejsť na stránku', + 'latest_episodes' => 'Posledné časti', + 'see_all_episodes' => 'Pozrieť všetky časti', + 'draft' => 'Koncept', + 'messages' => [ + 'createSuccess' => 'Podcast úspešne vytvorený!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast už je aktualizovaný.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Identita podcastu', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Identita vo Fediverse', + + 'cover' => 'Obal podcastu', + 'cover_size_hint' => 'Obrázok musí byť štvorcový a minimálne 1400px široký a vysoký.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Názov', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Typ', + 'episodic' => 'Epizodický', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Popis', + 'classification_section_title' => 'Zaradenie', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Jazyk', + 'category' => 'Kategória', + 'category_placeholder' => 'Vybrať kategóriu…', + 'other_categories' => 'Ostatné kategórie', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Obsahuje explicitný obsah?', + 'undefined' => 'neuvedené', + 'clean' => 'Čistá', + 'explicit' => 'Chúlostivé', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Kto spravuje tento podcast?', + 'owner_name' => 'Meno vlastníka', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Email vlastníka', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Vydavateľ', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Autorské práva', + 'location_section_title' => 'Umiestnenie', + 'location_section_subtitle' => 'O akom mieste/oblasti je tento podcast?', + 'location_name' => 'Názov oblasti, alebo adresa', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Prémiový obsah', + 'premium_by_default' => 'Epizódy musia byť predvolene nastavené ako prémiové', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnerstvo', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL adresa odkazu', + 'partner_image_url' => 'URL adresa obrázka', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Vytvoriť podcast', + 'submit_edit' => 'Uložiť podcast', + ], + 'category_options' => [ + 'uncategorized' => 'nezaradený', + 'arts' => 'Umenia', + 'business' => 'Podnikanie', + 'comedy' => 'Komédia', + 'education' => 'Vzdelanie', + 'fiction' => 'Fikcia', + 'government' => 'Štátna správa', + 'health_and_fitness' => 'Zdravie a fitnes', + 'history' => 'História', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Voľný čas', + 'music' => 'Hudba', + 'news' => 'Správy', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Veda', + 'society_and_culture' => 'Spoločnosť a kultúra', + 'sports' => 'Športy', + 'technology' => 'Technológia', + 'true_crime' => 'Skutočné krimi', + 'tv_and_film' => 'TV & Film', + 'books' => 'Knihy', + 'design' => 'Dizajn', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Jedlo', + 'performing_arts' => 'Divadelné umenie', + 'visual_arts' => 'Vizuálni umelci', + 'careers' => 'Kariéra', + 'entrepreneurship' => 'Podnikateľský', + 'investing' => 'Investičný', + 'management' => 'Manažment', + 'marketing' => 'Marketing', + 'non_profit' => 'Neziskový', + 'comedy_interviews' => 'Komediálne rozhovory', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Kurzy', + 'how_to' => 'Ako na to', + 'language_learning' => 'Učenie jazykov', + 'self_improvement' => 'Sebazdokonaľovanie', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Dráma', + 'science_fiction' => 'Vedecko-fantastické', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicínsky', + 'mental_health' => 'Duševné zdravie', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexualita', + 'education_for_kids' => 'Vzdelávanie pre deti', + 'parenting' => 'Rodičovstvo', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Príbehy pre deti', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Hry', + 'hobbies' => 'Záľuby', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Videohry', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Hudobná história', + 'music_interviews' => 'Hudobné rozhovory', + 'business_news' => 'Business News', + 'daily_news' => 'Denné správy', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politika', + 'sports_news' => 'Športové správy', + 'tech_news' => 'Technologické novinky', + 'buddhism' => 'Buddhism', + 'christianity' => 'Kresťanstvo', + 'hinduism' => 'Hinduizmus', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Náboženstvo', + 'spirituality' => 'Duchovno', + 'astronomy' => 'Astronómia', + 'chemistry' => 'Chémia', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Matematické', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Príroda', + 'physics' => 'Fyzika', + 'social_sciences' => 'Sociálne vedy', + 'documentary' => 'Dokumentárny', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Filozofia', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Vzťahy', + 'baseball' => 'Bejzbal', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Futbal', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Futbal', + 'swimming' => 'Plávanie', + 'tennis' => 'Tenis', + 'volleyball' => 'Volejbal', + 'wilderness' => 'Divočina', + 'wrestling' => 'Zápasnícky', + 'after_shows' => 'After Shows', + 'film_history' => 'Filmová história', + 'film_interviews' => 'Filmové rozhovory', + 'film_reviews' => 'Filmové recenzie', + 'tv_reviews' => 'TV recenzie', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Späť na podcastovú nástenku', + 'post' => 'Váš oznamovací príspevok', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Napíšte vašu správu…', + 'submit' => 'Zverejniť', + 'publication_date' => 'Dátum zverejnenia', + 'publication_method' => [ + 'now' => 'Hneď teraz', + 'schedule' => 'Naplánovať', + ], + 'scheduled_publication_date' => 'Dátum plánovaného zverejnenia', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Upraviť zverejnenie', + 'cancel_publication' => 'Zrušiť zverejnenie', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Napriek tomu zverejniť', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'konceptový režim', + 'not_published' => 'Tento podcast ešte nieje zverejnený.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Vymazať', + ], + 'by' => 'Od {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'Žiadna epizóda nenájdená!', + 'follow' => 'Nasledovať', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Aktivita', + 'episodes' => 'Časti', + 'sponsor' => 'Sponzor', + 'funding_links' => 'Odkazy na financovanie {podcastTitle}', + 'find_on' => 'Nájsť {podcastTitle} na', + 'listen_on' => 'Počúvajte na', +]; diff --git a/modules/Admin/Language/sk/PodcastNavigation.php b/modules/Admin/Language/sk/PodcastNavigation.php new file mode 100644 index 00000000..f90c67a2 --- /dev/null +++ b/modules/Admin/Language/sk/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Ísť na stránku podcastu', + 'rss_feed' => 'RSS kanál', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Úvod', + 'podcast-edit' => 'Upraviť podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Nahrané podcasty', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Časti', + 'episode-list' => 'Všetky časti', + 'episode-create' => 'Nová časť', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Prehrávače', + 'podcast-analytics-listening-time' => 'Čas počúvania', + 'podcast-analytics-time-periods' => 'Časové úseky', + 'monetization' => 'Monetization', + 'subscription-list' => 'Všetky odbery', + 'subscription-create' => 'Pridať odber', + 'contributors' => 'Prispievatelia', + 'contributor-list' => 'Všetci prispievatelia', + 'contributor-add' => 'Pridať prispievateľa', + 'broadcast' => 'Vysielanie', + 'platforms-podcasting' => 'Podcastové aplikácie', + 'platforms-social' => 'Sociálne siete', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/sk/Settings.php b/modules/Admin/Language/sk/Settings.php new file mode 100644 index 00000000..63441b6a --- /dev/null +++ b/modules/Admin/Language/sk/Settings.php @@ -0,0 +1,58 @@ + 'Všeobecné nastavenia', + 'instance' => [ + 'title' => 'Inštancia', + 'site_icon' => 'Ikona stránky', + 'site_icon_delete' => 'Odstrániť ikonu stránky', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Názov stránky', + 'site_description' => 'Popis stránky', + 'submit' => 'Uložiť', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Obrázky', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Vzhľad', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Karmínová', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Uložiť', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/sk/Soundbite.php b/modules/Admin/Language/sk/Soundbite.php new file mode 100644 index 00000000..6b118afb --- /dev/null +++ b/modules/Admin/Language/sk/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Zvukové ukážky', + 'soundbite' => 'Zvuková ukážka', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Názov zvukovej ukážky', + 'start_time' => 'Začiatok na', + 'duration' => 'Trvanie', + 'submit' => 'Vytvoriť zvukovú ukážku', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Vymazať zvukovú ukážku', +]; diff --git a/modules/Admin/Language/sk/Validation.php b/modules/Admin/Language/sk/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/sk/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/sk/VideoClip.php b/modules/Admin/Language/sk/VideoClip.php new file mode 100644 index 00000000..cfe35050 --- /dev/null +++ b/modules/Admin/Language/sk/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Stav', + 'queued' => 'v poradí', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'čaká', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Začiatok na', + 'duration' => 'Trvanie', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/sr-latn/AboutCastopod.php b/modules/Admin/Language/sr-latn/AboutCastopod.php new file mode 100644 index 00000000..66ccc2e3 --- /dev/null +++ b/modules/Admin/Language/sr-latn/AboutCastopod.php @@ -0,0 +1,22 @@ + 'O Castopod-u', + 'host_name' => 'Naziv hosta', + 'version' => 'Verzija Castopod-a', + 'php_version' => 'PHP verzija', + 'os' => 'Operativni Sistem', + 'languages' => 'Jezici', + 'update_database' => 'Ažuriraj baze podataka', + 'messages' => [ + 'databaseUpdateSuccess' => 'Baza podataka je ažurirana!', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Breadcrumb.php b/modules/Admin/Language/sr-latn/Breadcrumb.php new file mode 100644 index 00000000..3376dedd --- /dev/null +++ b/modules/Admin/Language/sr-latn/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb polja', + config('Admin') + ->gateway => 'Početna', + 'podcasts' => 'podkasti', + 'episodes' => 'epizode', + 'subscriptions' => 'pretplate', + 'contributors' => 'saradnici', + 'pages' => 'stranice', + 'settings' => 'podešavanja', + 'theme' => 'tema', + 'about' => 'osnovni podaci', + 'add' => 'dodaj', + 'new' => 'nov', + 'edit' => 'izmeni', + 'persons' => 'osobe', + 'publish' => 'objavi', + 'publish-edit' => 'uredi objavu', + 'publish-date-edit' => 'uredi datum objave', + 'unpublish' => 'ukolni objavu', + 'delete' => 'obriši', + 'remove' => 'ukloni', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blokirani nalozi', + 'blocked-domains' => 'blokirani domeni', + 'users' => 'korisnici', + 'my-account' => 'moj nalog', + 'change-password' => 'promenite lozinku', + 'imports' => 'uvozi', + 'sync-feeds' => 'sinhronizuj snabdevače', + 'platforms' => 'platforme', + 'social' => 'društvene mreže', + 'funding' => 'finansiranje', + 'monetization-other' => 'druga monetizacija', + 'analytics' => 'analitika', + 'locations' => 'lokacije', + 'webpages' => 'veb strane', + 'unique-listeners' => 'jedinstveni slušaoci', + 'players' => 'plejeri', + 'listening-time' => 'ukupno vreme slušanja', + 'time-periods' => 'vremenski periodi', + 'soundbites' => 'zvučni isečci', + 'video-clips' => 'video isečci', + 'embed' => 'embedovan plejer', + 'notifications' => 'obaveštenja', + 'suspend' => 'obustavi', +]; diff --git a/modules/Admin/Language/sr-latn/Charts.php b/modules/Admin/Language/sr-latn/Charts.php new file mode 100644 index 00000000..cb90b13b --- /dev/null +++ b/modules/Admin/Language/sr-latn/Charts.php @@ -0,0 +1,41 @@ + 'Preuzimanja epizode po servisu (za prošlu nedelju)', + 'by_player_weekly' => 'Preuzimanja epizode po plejeru (za prošlu nedelju)', + 'by_player_yearly' => 'Preuzimanja epizode po plejeru (za prošlu godinu)', + 'by_device_weekly' => 'Preuzimanja epizode po uređaju (za prošlu nedelju)', + 'by_os_weekly' => 'Preuzimanja epizode po operativnom sistemu (za prošlu nedelju)', + 'podcast_by_region' => 'Preuzimanja epizode po regionu (za prošlu nedelju)', + 'unique_daily_listeners' => 'Svakodnevni jedinstveni slušaoci', + 'unique_monthly_listeners' => 'Mesečni jedinstveni slušaoci', + 'by_browser' => 'Korišćenje veb stranica od strane pretraživača (za prošlu nedelju)', + 'podcast_by_day' => 'Dnevno preuzimanje epizoda', + 'podcast_by_month' => 'Mesečno preuzimanje epizoda', + 'episode_by_day' => 'Dnevno preuzimanje epizoda (prvih 60 dana)', + 'episode_by_month' => 'Mesečno preuzimanje epizoda', + 'episodes_by_day' => + 'Preuzimanja poslednjih 5 epizoda (u prvih 60 dana)', + 'by_country_weekly' => 'Preuzimanja epizode po državi (za prošlu nedelju)', + 'by_country_yearly' => 'Preuzimanja epizode po državi (za prošlu godinu)', + 'by_domain_weekly' => 'Posete veb stranicama prema izvoru (za prošlu nedelju)', + 'by_domain_yearly' => 'Posete veb stranicama prema izvoru (za prošlu godinu)', + 'by_entry_page' => 'Posete veb stranicama prema odredišnoj stranici (za prošlu nedelju)', + 'podcast_bots' => 'Botovi (pokretači)', + 'daily_listening_time' => 'Dnevno kumulativno vreme slušanja', + 'monthly_listening_time' => 'Mesečno kumulativno vreme slušanja', + 'by_weekday' => 'Po danu u nedelji (za poslednjih 60 dana)', + 'by_hour' => 'Po dobu dana (za poslednjih 60 dana)', + 'podcast_by_bandwidth' => 'Dnevno korišćen protok (u MB)', + 'total_storage_by_month' => 'Mesečni skladišni prostor (u MB)', + 'total_bandwidth_by_month' => 'Mesečno korišćen protok (u MB)', + 'total_bandwidth_by_month_limit' => 'Ograničeno na {totalBandwidth} mesečno', +]; diff --git a/modules/Admin/Language/sr-latn/Common.php b/modules/Admin/Language/sr-latn/Common.php new file mode 100644 index 00000000..8fc6f706 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Common.php @@ -0,0 +1,52 @@ + 'Da', + 'no' => 'Ne', + 'cancel' => 'Otkaži', + 'optional' => 'Opciono', + 'more' => 'Više', + 'no_data' => 'Nema pronađenih podataka!', + 'close' => 'Zatvori', + 'edit' => 'Izmeni', + 'copy' => 'Kopiraj', + 'copied' => 'Kopirano!', + 'home' => 'Početna stranica', + 'explicit' => 'Eksplicitno', + 'powered_by' => 'Pokreće {castopod}', + 'actions' => 'Akcije', + 'pageInfo' => 'Stranica {currentPage} od {pageCount}', + 'go_back' => 'Nazad', + 'forms' => [ + 'editor' => [ + 'write' => 'Piši', + 'preview' => 'Pregled', + 'help' => 'Pokreće markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Pritisni da odabereš', + 'loadingText' => 'Učitavanje…', + 'noResultsText' => 'Nije pronađen nijedan rezultat', + 'noChoicesText' => 'Nema opcija koje je moguće odabrati', + 'maxItemText' => 'Nije moguće dodati više stavki', + ], + 'upload_file' => 'Otpremite datoteku', + 'remote_url' => 'Daljinski URL', + 'save' => 'Sačuvaj', + ], + 'play_episode_button' => [ + 'play' => 'Pusti', + 'playing' => 'Reprodukujem', + ], + 'size_limit' => 'Limit veličine: {0}.', + 'choose_interact' => 'Odaberite način interakcije', + 'view' => 'Pogledaj', +]; diff --git a/modules/Admin/Language/sr-latn/Countries.php b/modules/Admin/Language/sr-latn/Countries.php new file mode 100644 index 00000000..64b97465 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Countries.php @@ -0,0 +1,264 @@ + 'Andora', + 'AE' => 'Ujedinjeni Arapski Emirati', + 'AF' => 'Afganistan', + 'AG' => 'Antiga i Barbuda', + 'AI' => 'Angvila', + 'AL' => 'Albanija', + 'AM' => 'Jermenija', + 'AO' => 'Angola', + 'AQ' => 'Antarktik', + 'AR' => 'Argentina', + 'AS' => 'Američka Samoa', + 'AT' => 'Austrija', + 'AU' => 'Australija', + 'AW' => 'Aruba', + 'AX' => 'Olandska Ostrva', + 'AZ' => 'Azerbejdžan', + 'BA' => 'Bosna i Hercegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladeš', + 'BE' => 'Bеlgija', + 'BF' => 'Burkina Faso', + 'BG' => 'Bugarska', + 'BH' => 'Bahrеin', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Sveti Bartolomej', + 'BM' => 'Bermuda', + 'BN' => 'Bruneji Darusalam', + 'BO' => 'Bolivija, Višenacionalna Država', + 'BQ' => 'Bonеr, Svеti Eustahijе i Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahami', + 'BT' => 'Butan', + 'BV' => 'Ostrvo Buve', + 'BW' => 'Bocvana', + 'BY' => 'Bеlorusija', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Kokosova (Kilingova) Ostrva', + 'CD' => 'Demokratska Republika Kongo', + 'CF' => 'Centralnoafrička Republika', + 'CG' => 'Kongo', + 'CH' => 'Švajcarska', + 'CI' => "Obala Slonovače", + 'CK' => 'Kukova ostrva', + 'CL' => 'Čilе', + 'CM' => 'Kamerun', + 'CN' => 'Kina', + 'CO' => 'Kolumbija', + 'CR' => 'Kostarika', + 'CU' => 'Kuba', + 'CV' => 'Zelenortska Ostrva', + 'CW' => 'Kurasao', + 'CX' => 'Uskršnja ostrva', + 'CY' => 'Kipar', + 'CZ' => 'Češka Republika', + 'DE' => 'Nemačka', + 'DJ' => 'Džibuti', + 'DK' => 'Danska', + 'DM' => 'Dominika', + 'DO' => 'Dominikanska Republika', + 'DZ' => 'Alžir', + 'EC' => 'Ekvador', + 'EE' => 'Estonija', + 'EG' => 'Egipat', + 'EH' => 'Zapadna Sahara', + 'ER' => 'Eritreja', + 'ES' => 'Španija', + 'ET' => 'Etiopija', + 'FI' => 'Finska', + 'FJ' => 'Fidži', + 'FK' => 'Foklandska ostrva (Malvini)', + 'FM' => 'Savezne države Mikronezije', + 'FO' => 'Farska Ostrva', + 'FR' => 'Francuska', + 'GA' => 'Gabon', + 'GB' => 'Ujedinjeno Kraljevstvo', + 'GD' => 'Grenada', + 'GE' => 'Gruzija', + 'GF' => 'Francuska Gvajana', + 'GG' => 'Gernzi', + 'GH' => 'Gana', + 'GI' => 'Gibraltar', + 'GL' => 'Grеnland', + 'GM' => 'Gambija', + 'GN' => 'Gvineja', + 'GP' => 'Gvadelupe', + 'GQ' => 'Ekvatorijalna Gvineja', + 'GR' => 'Grčka', + 'GS' => 'Južna Džordžija i Južna Sendvič Ostrva', + 'GT' => 'Gvatemala', + 'GU' => 'Guam', + 'GW' => 'Gvineja-Bisao', + 'GY' => 'Gvajana', + 'HK' => 'Hong Kong', + 'HM' => 'Ostrva Herd i Makdonald', + 'HN' => 'Honduras', + 'HR' => 'Hrvatska', + 'HT' => 'Haiti', + 'HU' => 'Mađarska', + 'ID' => 'Indonezija', + 'IE' => 'Irska', + 'IL' => 'Izrael', + 'IM' => 'Ostrvo Man', + 'IN' => 'Indija', + 'IO' => 'Britanska Territorija u Indijskom Okeanu', + 'IQ' => 'Irak', + 'IR' => 'Islamska Republika Iran', + 'IS' => 'Island', + 'IT' => 'Italija', + 'JE' => 'Džersi', + 'JM' => 'Jamajka', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenija', + 'KG' => 'Kirgistan', + 'KH' => 'Kambodža', + 'KI' => 'Kiribati', + 'KM' => 'Komorska Ostrva', + 'KN' => 'Sveti Kits i Nevis', + 'KP' => "Demokratska Narodna Republika Koreja", + 'KR' => 'Republika Koreja', + 'KW' => 'Kuvajt', + 'KY' => 'Kajmanska ostrva', + 'KZ' => 'Kazahstan', + 'LA' => "Laos", + 'LB' => 'Liban', + 'LC' => 'Sveta Lucija', + 'LI' => 'Lihtenštajn', + 'LK' => 'Šri Lanka', + 'LR' => 'Liberija', + 'LS' => 'Lesoto', + 'LT' => 'Litvanija', + 'LU' => 'Luksemburg', + 'LV' => 'Letonija', + 'LY' => 'Libija', + 'MA' => 'Maroko', + 'MC' => 'Monako', + 'MD' => 'Republika Moldavija', + 'ME' => 'Crna Gora', + 'MF' => 'Sveti Martin (Francuski deo)', + 'MG' => 'Madagaskar', + 'MH' => 'Maršalska Ostrva', + 'MK' => 'Severna Makedonija', + 'ML' => 'Mali', + 'MM' => 'Mijanmar', + 'MN' => 'Mongolija', + 'MO' => 'Makao', + 'MP' => 'Severna Marijanska Ostrva', + 'MQ' => 'Martinik', + 'MR' => 'Mauritanija', + 'MS' => 'Montserat', + 'MT' => 'Malta', + 'MU' => 'Mauricijus', + 'MV' => 'Maldivi', + 'MW' => 'Malavi', + 'MX' => 'Meksiko', + 'MY' => 'Malezija', + 'MZ' => 'Mozambik', + 'N/A' => 'Nije primenjivo (Lokalna IP…)', + 'NA' => 'Namibija', + 'NC' => 'Nova Kaledonija', + 'NE' => 'Niger', + 'NF' => 'Ostrvo Norfolk', + 'NG' => 'Nigerija', + 'NI' => 'Nikaragva', + 'NL' => 'Holandija', + 'NO' => 'Norveška', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Nijue', + 'NZ' => 'Novi Zeland', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Francuska Polinezija', + 'PG' => 'Papua Nova Gvinеja', + 'PH' => 'Filipini', + 'PK' => 'Pakistan', + 'PL' => 'Poljska', + 'PM' => 'Sen Pjer i Mikelon', + 'PN' => 'Pitkern', + 'PR' => 'Portoriko', + 'PS' => 'Palestina', + 'PT' => 'Portugalija', + 'PW' => 'Palau', + 'PY' => 'Paragvaj', + 'QA' => 'Katar', + 'RE' => 'Rejunion', + 'RO' => 'Rumunija', + 'RS' => 'Srbija', + 'RU' => 'Ruska Federacija', + 'RW' => 'Ruanda', + 'SA' => 'Saudijska Arabija', + 'SB' => 'Solomonova ostrva', + 'SC' => 'Sejšeli', + 'SD' => 'Sudan', + 'SE' => 'Švedska', + 'SG' => 'Singapur', + 'SH' => 'Sveta Helena, Asension i Tristan da Kunja', + 'SI' => 'Slovеnija', + 'SJ' => 'Svalbard i Jan Majen', + 'SK' => 'Slovačka', + 'SL' => 'Sijera Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalija', + 'SR' => 'Surinam', + 'SS' => 'Južni Sudan', + 'ST' => 'Sao Tomе i Prinsipе', + 'SV' => 'Salvador', + 'SX' => 'Sveti Martin (Holandski deo)', + 'SY' => 'Sirijska Arapska Republika', + 'SZ' => 'Svazilеnd', + 'TC' => 'Tеrks i Kеjkos', + 'TD' => 'Čad', + 'TF' => 'Francuske Južne Teritorije', + 'TG' => 'Togo', + 'TH' => 'Таjland', + 'TJ' => 'Tadžikistan', + 'TK' => 'Tokelau', + 'TL' => 'Istočni Timor', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunis', + 'TO' => 'Tonga', + 'TR' => 'Turska', + 'TT' => 'Trinidad i Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Tajvan, Kineska provincija', + 'TZ' => 'Ujedinjena Republika Tanzanija', + 'UA' => 'Ukrajina', + 'UG' => 'Uganda', + 'UM' => 'Mala spoljna ostrva Sjedinjenih Američkih Država', + 'US' => 'Sjеdinjеnе Državе', + 'UY' => 'Urugvaj', + 'UZ' => 'Uzbekistan', + 'VA' => 'Sveta stolica (Grad-država Vatikan)', + 'VC' => 'Sveti Vinsent i Grenadini', + 'VE' => 'Venecuela', + 'VG' => 'Devičanska ostrva', + 'VI' => 'Devičanska Ostrva, S.A.D.', + 'VN' => 'Vijetnam', + 'VU' => 'Vanuatu', + 'WF' => 'Valis i Futuna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Majote', + 'ZA' => 'Južna Afrika', + 'ZM' => 'Zambija', + 'ZW' => 'Zimbabve', +]; diff --git a/modules/Admin/Language/sr-latn/Dashboard.php b/modules/Admin/Language/sr-latn/Dashboard.php new file mode 100644 index 00000000..8761ee1b --- /dev/null +++ b/modules/Admin/Language/sr-latn/Dashboard.php @@ -0,0 +1,28 @@ + 'Kontrolna tabla za administratora', + 'welcome_message' => 'Dobrodošli u deo za administratore!', + 'podcasts' => [ + 'title' => 'Podkasti', + 'not_found' => 'Nemate objavljen podkast', + 'last_published' => 'Poslednja objava {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Epizode', + 'not_found' => 'Nemate objavljene epizode', + 'last_published' => 'Poslednja objava {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Prostor', + 'subtitle' => '{totalUploaded} od {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Episode.php b/modules/Admin/Language/sr-latn/Episode.php new file mode 100644 index 00000000..9ac56547 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Episode.php @@ -0,0 +1,225 @@ + 'Sezona {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Epizoda {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Sezona {seasonNumber} epizoda {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}:E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# komentar} + other {# komentara} + }', + 'all_podcast_episodes' => 'Sve epizode podkasta', + 'back_to_podcast' => 'Nazad na podkast', + 'edit' => 'Izmeni', + 'preview' => 'Pregled', + 'publish' => 'Objavi', + 'publish_edit' => 'Uredi objavu', + 'publish_date_edit' => 'Uredi datum objave', + 'unpublish' => 'Opozovi objavu', + 'publish_error' => 'Epizoda je već objavljena.', + 'publish_edit_error' => 'Epizoda je već objavljena.', + 'publish_cancel_error' => 'Epizoda je već objavljena.', + 'publish_date_edit_error' => 'Epizoda još uvek nije objavljena, ne možete urediti datum objave.', + 'publish_date_edit_future_error' => 'Datum objavljivanja epizode može se podesiti samo na pređašnji datum. Ukoliko želite da ponovo zakažete objavu epizode u budućnosti, morate prvo opozvati njenu objavu.', + 'publish_date_edit_success' => 'Datum objave epizode je uspešno uređen!', + 'unpublish_error' => 'Epizoda nije objavljena.', + 'delete' => 'Obriši', + 'go_to_page' => 'Idi na stranu', + 'create' => 'Dodaj epizodu', + 'publication_status' => [ + 'published' => 'Objavljeno', + 'with_podcast' => 'Objavljeno', + 'scheduled' => 'Zakazano', + 'not_published' => 'Neobjavljeno', + ], + 'with_podcast_hint' => 'Objaviti u isto vreme kad i podkast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Traži epizodu', + 'clear' => 'Očisti pretragu', + 'submit' => 'Pretraga', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# epizoda} + other {# epizode} + }', + 'episode' => 'Epizoda', + 'visibility' => 'Vidljivost', + 'downloads' => 'Preuzimanja', + 'comments' => 'Komentari', + 'actions' => 'Akcije', + ], + 'messages' => [ + 'createSuccess' => 'Epizoda je uspešno kreirana!', + 'editSuccess' => 'Epizoda je uspešno ažurirana!', + 'publishSuccess' => '{publication_status, select, + published {Epizoda je uspešno objavljena!} + scheduled {Epizoda je uspešno zakazana!} + with_podcast {Ova epizoda će biti objavljena u isto vreme kad i podkast.} + other {Ova epizoda nije objavljena.} + }', + 'publishCancelSuccess' => 'Objavljivanje epizode je uspešno otkazano!', + 'unpublishBeforeDeleteTip' => 'Morate opozvati objavljivanje epizode pre nego što je izbrišete.', + 'scheduleDateError' => 'Morate zakazati datum objave!', + 'deletePublishedEpisodeError' => 'Molimo vas opozovite objavu epizode pre nego što je izbrišete.', + 'deleteSuccess' => 'Epizoda uspešno izbrisana!', + 'deleteError' => 'Neuspešno brisanje {type, select, + transcript {transkripta} + chapters {poglavlja} + image {omota} + audio {zvuka} + other {medija} + }.', + 'deleteFileError' => 'Neuspešno brisanje {type, select, + transcript {transkripta} + chapters {poglavlja} + image {omota} + audio {zvuka} + other {medija} + } datoteke {file_key}. Možete je ukloniti ručno sa vašeg diska.', + 'sameSlugError' => 'Odabrano URL ime (slug) epizode već postoji.', + ], + 'form' => [ + 'file_size_error' => + 'Veličina vaše datoteke je prevelika! Maksimalna veličina je {0}. Povećajte `memory_limit`, `upload_max_filesize` i `post_max_size` vrednosti u vašoj datoteci php konfiguracije, potom ponovo pokrenite veb server da bi ste otpremili datoteku.', + 'audio_file' => 'Zvučna datoteka', + 'audio_file_hint' => 'Odaberite .mp3 ili .m4a zvučnu datoteku.', + 'info_section_title' => 'Informacije o epizodi', + 'cover' => 'Omot epizode', + 'cover_hint' => + 'Ukoliko ne postavite omot epizode, koristiće se omot podkasta.', + 'cover_size_hint' => 'Omot mora biti kvadratnog oblika i minimum 1400px širok i visok.', + 'title' => 'Naslov', + 'title_hint' => + 'Treba sadržati jasan i koncizan naziv epizode. Nemojte upisivati broj sezone ili epizode ovde.', + 'permalink' => 'Trajni link', + 'season_number' => 'Sezona', + 'episode_number' => 'Epizoda', + 'type' => [ + 'label' => 'Vrsta', + 'full' => 'Cela', + 'full_hint' => 'Kompletan sadržaj (epizoda)', + 'trailer' => 'Najava', + 'trailer_hint' => 'Kratak, promotivni deo sadržaja koji predstavlja pregled aktuelne emisije', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Dodatni sadržaj za emisiju (na primer, informacije iza scene ili intervjui sa glumcima) ili unakrsni promotivni sadržaj za drugu emisiju', + ], + 'premium_title' => 'Premium', + 'premium' => 'Epizoda mora biti dostupna samo premium pretplatnicima', + 'parental_advisory' => [ + 'label' => 'Roditeljsko savetovanje', + 'hint' => 'Da li epizoda sadrži eksplicitan sadržaj?', + 'undefined' => 'nedefinisano', + 'clean' => 'Čisto', + 'explicit' => 'Eksplicitno', + ], + 'show_notes_section_title' => 'Prikaži beleške', + 'show_notes_section_subtitle' => + 'Do 4000 znakova, budite jasni i sažeti. Beleške pomažu potencijalnim slušaocima da pronađu epizodu.', + 'description' => 'Opis', + 'description_footer' => 'Podnožje opisa', + 'description_footer_hint' => + 'Ovaj tekst se dodaje na kraj opisa svake epizode, ovo je pravo mesto za vaše linkove ka društvenim mrežama naprimer.', + 'additional_files_section_title' => 'Dodatne datoteke', + 'additional_files_section_subtitle' => + 'Ove datoteke mogu biti korišćene od strane drugih platformi radi boljeg iskustva vaše publike. Pogledajte {podcastNamespaceLink} za više informacija.', + 'location_section_title' => 'Lokacija', + 'location_section_subtitle' => 'O kom mestu je ova epizoda?', + 'location_name' => 'Ime ili adresa lokacije', + 'location_name_hint' => 'Ovo može biti prava ili fiktivna lokacija', + 'transcript' => 'Transkript (titlovi)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Preuzmi transkript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Udaljeni Url za transkript', + 'transcript_file_delete' => 'Obriši datoteku transkripta', + 'chapters' => 'Poglavlja', + 'chapters_hint' => 'Datoteka mora biti u JSON Poglavlja formatu.', + 'chapters_download' => 'Preuzmi poglavlja', + 'chapters_file' => 'Datoteka poglavlja', + 'chapters_remote_url' => 'Udaljeni Url za datoteku poglavlja', + 'chapters_file_delete' => 'Obriši datoteku poglavlja', + 'advanced_section_title' => 'Napredni parametri', + 'advanced_section_subtitle' => + 'Ukoliko su vam potrebni RSS tagovi koje Castopod ne obrađuje, postavite ih ovde.', + 'custom_rss' => 'Posebni RSS tagovi epizode', + 'custom_rss_hint' => 'Ovo će biti ubačeno u ❬item❭ tag.', + 'block' => 'Epizoda treba biti sakriivena u javnim katalozima', + 'block_hint' => + 'Prikazan ili sakriven status epizode: ukoliko uključite ovu opciju onemogućavate prikazivanje vaše epizode na paltformama za slušanje podkasta kao što su Apple Podcasts, Google Podcasts i sličnim direktorijima. (Nije zagarantovano)', + 'submit_create' => 'Kreiraj epizodu', + 'submit_edit' => 'Sačuvaj epizodu', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Nazad na komandnu tablu epizode', + 'post' => 'Najava vaše objave', + 'post_hint' => + "Napišite poruku da najavite objavu vaše epizode. Poruka će biti poslata svim vašim pratiocima u fediversu i istaknuta na stranici vašeg podkasta.", + 'message_placeholder' => 'Napišite poruku…', + 'publication_date' => 'Datum objavljivanja', + 'publication_method' => [ + 'now' => 'Sada', + 'schedule' => 'Raspored', + 'with_podcast' => 'Objavi uz podkast', + ], + 'scheduled_publication_date' => 'Planiran datum objave', + 'scheduled_publication_date_clear' => 'Ukloni datum objave', + 'scheduled_publication_date_hint' => + 'Možete zakazati objavu epizode u budućnosti. Ovo polje mora biti popunjeno u YYYY-MM-DD HH:mm formatu', + 'submit' => 'Objavi', + 'submit_edit' => 'Uredi objavu', + 'cancel_publication' => 'Poništi objavu', + 'message_warning' => 'Niste napisali poruku za najavu objave!', + 'message_warning_hint' => 'Poruka povećava šanse za angažovanjem na društvenim mrežama, rezultirajući u većoj vidljivosti vaše epizode.', + 'message_warning_submit' => 'Objavi svakako', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Novi datum objavljivanja', + 'new_publication_date_hint' => 'Mora biti podešeno na prošli datum.', + 'submit' => 'Uredi datum objavljivanja', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Opozivanje objavljivanja epizode će obrisati sve komentare i obajve povezane sa eppizodom i ukloniti je i RSS feed-a podkasta.", + 'understand' => 'Razumem, želim da opozovem objavu epizode', + 'submit' => 'Opozovi objavu', + ], + 'delete_form' => [ + 'disclaimer' => + "Brisanje epizode će obrisati sve medijske datoteke, komentare, video i zvučne isečke povezane sa njom.", + 'understand' => 'Razumem, želim da obrišem epizodu', + 'submit' => 'Obriši', + ], + 'embed' => [ + 'title' => 'Embedovan plejer', + 'label' => + 'Odaberite boju teme, kopirajte embedovan plejer i nalepite ga na vaš sajt.', + 'clipboard_iframe' => 'Kopirajte kod embedovanog plejera', + 'clipboard_url' => 'Kopirajte adresu', + 'dark' => 'Tamna', + 'dark-transparent' => 'Tamna providna', + 'light' => 'Svetla', + 'light-transparent' => 'Svetla providna', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'režim nacrta', + 'text' => '{publication_status, select, + published {Ova epizoda još uvek nije objavljena.} + scheduled {Ova epizoda je zakazana za {publication_date}.} + with_podcast {Ova epizoda će biti objavljena kad i podkast.} + other {Ova epizoda još uvek nije objavljena.} + }', + 'preview' => 'Pregled', + ], +]; diff --git a/modules/Admin/Language/sr-latn/EpisodeNavigation.php b/modules/Admin/Language/sr-latn/EpisodeNavigation.php new file mode 100644 index 00000000..48cf7138 --- /dev/null +++ b/modules/Admin/Language/sr-latn/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Pogledaj stranicu epizode', + 'dashboard' => 'Kontrolna tabla epizode', + 'episode-view' => 'Početna', + 'episode-edit' => 'Uredi epizodu', + 'episode-persons-manage' => 'Uredi osobe', + 'embed-add' => 'Embedovan plejer', + 'clips' => 'Isečci', + 'video-clips-list' => 'Video isečci', + 'video-clips-create' => 'Novi video isečak', + 'soundbites-list' => 'Zvučni isečci', + 'soundbites-create' => 'Novi zvučni isečak', +]; diff --git a/modules/Admin/Language/sr-latn/Fediverse.php b/modules/Admin/Language/sr-latn/Fediverse.php new file mode 100644 index 00000000..77d2bd18 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Nalog ne može biti pronađen!', + 'blockActorSuccess' => '{actor} je blokiran!', + 'unblockActorSuccess' => '{actor} je blokiran!', + 'blockDomainSuccess' => '{domain} je blokiran!', + 'unblockDomainSuccess' => '{domain} je odblokiran!', + ], + 'blocked_actors' => 'Blokirani nalozi', + 'blocked_domains' => 'Blokirani domeni', + 'block_lists_form' => [ + 'handle' => 'Kvačica naloga', + 'handle_hint' => 'Unesi @username@domain nalog.', + 'domain' => 'Naziv domena', + 'submit' => 'Blokiraj!', + ], + 'list' => [ + 'actor' => 'Nalog', + 'domain' => 'Naziv domena', + 'unblock' => 'Odblokiraj', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Home.php b/modules/Admin/Language/sr-latn/Home.php new file mode 100644 index 00000000..b116bc70 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Home.php @@ -0,0 +1,14 @@ + 'Svi podkasti', + 'no_podcast' => 'Nema pronađenih podkasta', +]; diff --git a/modules/Admin/Language/sr-latn/Install.php b/modules/Admin/Language/sr-latn/Install.php new file mode 100644 index 00000000..65edca65 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Install.php @@ -0,0 +1,61 @@ + 'Ručna konfiguracija', + 'manual_config_subtitle' => + 'Napravite `.env` datoteku sa vašim podešavanjima i osvežite stranicu da bi ste nastavili instalaciju.', + 'form' => [ + 'instance_config' => 'Konfiguracija instance', + 'hostname' => 'Ime domaćina', + 'media_base_url' => 'URL medijske baze', + 'media_base_url_hint' => + 'Ako koristite CDN i/ili eksternu uslugu za analitiku, možete ih postaviti ovde.', + 'admin_gateway' => 'Administratorski izlaz', + 'admin_gateway_hint' => + 'Ruta za pristup kontrolnoj tabli administratora (eg. https://example.com/cp-admin).Podrazumevano je podešena na cp-admin, preporučujemo da je promenite iz sigurnosnih razloga.', + 'auth_gateway' => 'Auth izlaz', + 'auth_gateway_hint' => + 'Ruta za pristup stranicama za potvrdu identiteta (eg. https://example.com/cp-auth).Podrazumevano je podešena na cp-auth, preporučujemo da je promenite iz sigurnosnih razloga.', + 'database_config' => 'Konfiguracija baze podataka', + 'database_config_hint' => + 'Castopod mora da se poveže za vašom MySQL (ili MariaDB) bazom. Ukoliko ne posedujete potrebne informacije, molimo vas kontaktirajte administratora vašeg servera.', + 'db_hostname' => 'Ime hosta baze podataka', + 'db_name' => 'Ime baze podataka', + 'db_username' => 'Korisničko ime baze podataka', + 'db_password' => 'Lozinka baze podataka', + 'db_prefix' => 'Prefiks baze', + 'db_prefix_hint' => + "Prefiks imena tabela Castopod-a, ne diraj ako ne znaš šta znači.", + 'cache_config' => 'Konfiguracija keša', + 'cache_config_hint' => + 'Izaberite željeni obrađivač keša. Ostavite je kao podrazumevanu vrednost ako nemate pojma šta to znači.', + 'cache_handler' => 'Obrađivač keša', + 'cacheHandlerOptions' => [ + 'file' => 'Datoteka', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Sledeće', + 'submit' => 'Završi instalaciju', + 'create_superadmin' => 'Kreiraj svoj nalog super administratora', + 'email' => 'E-pošta', + 'username' => 'Korisničko ime', + 'password' => 'Lozinka', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Vaš nalog superadmina je uspešno kreiran. Prijavite se da biste započeli podkasting!', + 'databaseConnectError' => + 'Castopod nije mogao da se poveže sa vašom bazom podataka. Uredite konfiguraciju baze podataka i pokušajte ponovo.', + 'writeError' => + "Nije moguće kreirati/upisati datoteku `.env`. Morate je kreirati ručno prateći šablon datoteke `.env.example` u Castopod-ovom paketu.", + ], +]; diff --git a/modules/Admin/Language/sr-latn/Navigation.php b/modules/Admin/Language/sr-latn/Navigation.php new file mode 100644 index 00000000..bc4c5518 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Navigation.php @@ -0,0 +1,44 @@ + 'Uključite bočnu traku', + 'go_to_website' => 'Idi na sajt', + 'go_to_admin' => 'Idi na administratora', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Kontrolna tabla', + 'admin' => 'Početna', + 'podcasts' => 'Podkasti', + 'podcast-list' => 'Svi podkasti', + 'podcast-create' => 'Novi podkast', + 'all-podcast-imports' => 'Uvozi podkasta', + 'podcast-imports-add' => 'Uvezi podkast', + 'persons' => 'Osobe', + 'person-list' => 'Sve osobe', + 'person-create' => 'Nova osoba', + 'fediverse' => 'Fediverzum', + 'fediverse-blocked-actors' => 'Blokirani nalozi', + 'fediverse-blocked-domains' => 'Blokirani domeni', + 'users' => 'Korisnici', + 'user-list' => 'Svi korisnici', + 'user-create' => 'Novi korisnik', + 'pages' => 'Stranice', + 'page-list' => 'Sve stranice', + 'page-create' => 'Nova Stranica', + 'settings' => 'Podešavanja', + 'settings-general' => 'Opšte', + 'settings-theme' => 'Tema', + 'admin-about' => 'Osnovni podaci', + 'account' => [ + 'my-account' => 'Moj nalog', + 'change-password' => 'Promenite lozinku', + 'logout' => 'Odjava', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Notifications.php b/modules/Admin/Language/sr-latn/Notifications.php new file mode 100644 index 00000000..dc79e82a --- /dev/null +++ b/modules/Admin/Language/sr-latn/Notifications.php @@ -0,0 +1,19 @@ + 'Obaveštenja', + 'reply' => '{actor_username} odgovara na tvoju objavu', + 'favourite' => '{actor_username} dodaje tvoju objavu u omiljene', + 'reblog' => '{actor_username} deli tvoju objavu', + 'follow' => '{actor_username} vas sada prati', + 'no_notifications' => 'Nema obaveštenja', + 'mark_all_as_read' => 'Označi svе kao pročitano', +]; diff --git a/modules/Admin/Language/sr-latn/Page.php b/modules/Admin/Language/sr-latn/Page.php new file mode 100644 index 00000000..224fa82e --- /dev/null +++ b/modules/Admin/Language/sr-latn/Page.php @@ -0,0 +1,30 @@ + 'Natrag na početnu', + 'page' => 'Stranica', + 'all_pages' => 'Sve stranice', + 'create' => 'Nova Stranica', + 'go_to_page' => 'Idi na stranicu', + 'edit' => 'Izmeni stranicu', + 'delete' => 'Obriši stranicu', + 'form' => [ + 'title' => 'Naslov', + 'permalink' => 'Trajni link', + 'content' => 'Sadržaj', + 'submit_create' => 'Napravi stranicu', + 'submit_edit' => 'Sačuvaj', + ], + 'messages' => [ + 'createSuccess' => 'Stranica “{pageTitle}” je uspešno napravljena!', + 'editSuccess' => 'Stranica je uspešno ažurirana!', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Pager.php b/modules/Admin/Language/sr-latn/Pager.php new file mode 100644 index 00000000..421dbe64 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Pager.php @@ -0,0 +1,21 @@ + 'Navigacija po stranicama', + 'first' => 'Prva', + 'previous' => 'Prеthodna', + 'next' => 'Sledeća', + 'last' => 'Poslednja', + 'older' => 'Starije', + 'newer' => 'Novije', + 'invalidTemplate' => '{0} nije važeći šablon za stranice.', + 'invalidPaginationGroup' => '{0} nije važeći šablon za grupu paginacija.', +]; diff --git a/modules/Admin/Language/sr-latn/Person.php b/modules/Admin/Language/sr-latn/Person.php new file mode 100644 index 00000000..e2e40df6 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Person.php @@ -0,0 +1,65 @@ + 'Osobe', + 'all_persons' => 'Sve osobe', + 'no_person' => 'Niko nije pronađen!', + 'create' => 'Kreiraj novu osobu', + 'view' => 'Pogledaj osobu', + 'edit' => 'Izmeni osobu', + 'delete' => 'Obriši osobu', + 'messages' => [ + 'createSuccess' => 'Osoba je uspešno kreirana!', + 'editSuccess' => 'Osoba je uspešno izmenjena!', + 'deleteSuccess' => 'Osoba je uklonjena!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar mora biti kvadratnog oblika i minimum 400px širok i visok.', + 'full_name' => 'Puno ime', + 'full_name_hint' => 'Ovo je puno ime ili nadimak osobe.', + 'unique_name' => 'Jedinstveno ime', + 'unique_name_hint' => 'Koristi se za URL', + 'information_url' => 'Informacijski URL', + 'information_url_hint' => + 'Url ka relevantnim informacijama o osobi, kao što su naprimer njihova veb stranica ili profil na društvenim mrežama.', + 'submit_create' => 'Kreiraj novu osobu', + 'submit_edit' => 'Sačuvaj osobu', + ], + 'podcast_form' => [ + 'title' => 'Uredi osobe', + 'add_section_title' => 'Dodaj osobe ovom podkastu', + 'add_section_subtitle' => 'Možete odabrati nekoliko osoba i njihovih uloga.', + 'persons' => 'Osobe', + 'persons_hint' => + 'Možete odabrati jednu ili nekoliko osoba sa istim ulogama. Morate prvo kreirati osobe.', + 'roles' => 'Uloge', + 'roles_hint' => + 'Možete odabrati jednu, nekoliko ili nijednu ulogu za osobu.', + 'submit_add' => 'Dodaj osobu(e)', + 'remove' => 'Ukloni', + ], + 'episode_form' => [ + 'title' => 'Upravljaj osobama', + 'add_section_title' => 'Dodaj osobe ovoj epizodi', + 'add_section_subtitle' => 'Možete odabrati nekoliko osoba i njihovih uloga.', + 'persons' => 'Osobe', + 'persons_hint' => + 'Možete odabrati jednu ili nekoliko osoba sa istim ulogama. Morate prvo kreirati osobe.', + 'roles' => 'Uloge', + 'roles_hint' => + 'Možete odabrati jednu, nekoliko ili nijednu ulogu za osobu.', + 'submit_add' => 'Dodaj osobu(e)', + 'remove' => 'Ukloni', + ], + 'credits' => 'Zasluge', +]; diff --git a/modules/Admin/Language/sr-latn/Platforms.php b/modules/Admin/Language/sr-latn/Platforms.php new file mode 100644 index 00000000..0e895f03 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podkasting platforme', + 'social' => 'Društvene mreže', + 'funding' => 'Podrška', + ], + 'website' => 'Veb stranica', + 'home_url' => 'Idi na {platformName} stranicu', + 'register' => 'Rеgistrujte sе', + 'submit_url' => 'Dodaj svoj podkast na {platformName}', + 'your_link' => 'Vaš link', + 'your_id' => [ + 'podcasting' => 'Tvoj ID', + 'social' => 'Tvoj ID', + 'funding' => 'Tvoj PNA', + ], + 'your_cta' => 'Tvoj poziv na akciju', + 'visible' => 'Prikaži na naslovnoj strani podkasta?', + 'on_embed' => 'Prikaži na embedovanom plejeru?', + 'remove' => 'Ukloni {platformName}', + 'submit' => 'Sačuvaj', + 'messages' => [ + 'updateSuccess' => 'Veze sa platformama su uspešno ažurirane!', + 'removeLinkSuccess' => 'Veza ka platformi je izbrisana.', + 'removeLinkError' => + 'Vezu sa platformom nije moguće ukloniti. Probajte ponovo.', + ], + 'description' => [ + 'podcasting' => 'ID podkasta na ovoj platformi', + 'social' => 'ID naloga podkasta na ovoj platformi', + 'funding' => 'Poruka poziva na akciju', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Podcast.php b/modules/Admin/Language/sr-latn/Podcast.php new file mode 100644 index 00000000..7926e093 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Podcast.php @@ -0,0 +1,330 @@ + 'Svi podkasti', + 'no_podcast' => 'Nema pronađenih podkasta!', + 'create' => 'Napravi podkast', + 'import' => 'Uvezi podkast', + 'all_imports' => 'Uvozi podkasta', + 'new_episode' => 'Nova epizoda', + 'view' => 'Pogledaj epizodu', + 'edit' => 'Uredi podkast', + 'publish' => 'Objavi podkast', + 'publish_edit' => 'Uredi objavu', + 'delete' => 'Obriši podkast', + 'see_episodes' => 'Pogledaj epizode', + 'see_contributors' => 'Pogledaj saradnike', + 'monetization_other' => 'Druga monetizacija', + 'go_to_page' => 'Idi na stranicu', + 'latest_episodes' => 'Najnovije epizode', + 'see_all_episodes' => 'Prikaži sve epizode', + 'draft' => 'Nacrt', + 'messages' => [ + 'createSuccess' => 'Podkast uspešno kreiran!', + 'editSuccess' => 'Podkast je uspešno ažuriran!', + 'importSuccess' => 'Podkast je uspešno uvezen!', + 'deleteSuccess' => 'Podkast @{podcast_handle} je uspešno obrisan!', + 'deletePodcastMediaError' => 'Neuspešno brisanje podkast {type, select, + cover {omota} + banner {banera} + other {medija} + }.', + 'deleteEpisodeMediaError' => 'Neuspešno brisanje {episode_slug} {type, select, + transcript {transkripta} + chapters {poglavlja} + image {omota} + audio {zvuka} + other {medija} + }.', + 'deletePodcastMediaFolderError' => 'Neuspešno brisanje podkast medija direktorijuma {folder_path}. Možete ga ručno ukloniti sa diska.', + 'podcastFeedUpdateSuccess' => 'Uspešno ažuriranje: {number_of_new_episodes, plural, + one {# epizoda je} + other {# epizode su} + } deo podkasta!', + 'podcastFeedUpToDate' => 'Podkast je već ažuriran.', + 'publishError' => 'Ovaj podkast je ili već objavljen ili zakazan za objavu.', + 'publishEditError' => 'Ovaj podkast nije zakazan za objavu.', + 'publishCancelSuccess' => 'Objavljivanje podkasta je uspešno otkazano!', + 'scheduleDateError' => 'Morate zakazati datum objave!', + ], + 'form' => [ + 'identity_section_title' => 'Identitet podkasta', + 'identity_section_subtitle' => 'Ova polja vam pomažu da budete prepoznati.', + 'fediverse_section_title' => 'Fedivers identitet', + + 'cover' => 'Omot podkasta', + 'cover_size_hint' => 'Omot mora biti kvadratnog oblika i minimum 1400px širok i visok.', + 'banner' => 'Baner podkasta', + 'banner_size_hint' => 'Baner mora imati odnos 3:1 i biti najmanje 1500px širok.', + 'banner_delete' => 'Obriši baner podkasta', + 'title' => 'Naslov', + 'handle' => 'Ručka', + 'handle_hint' => + 'Koristi se radi identifikacije podkasta. Velika slova, mala slova, brojevi i donja crta su prihvatljivi.', + 'type' => [ + 'label' => 'Vrsta', + 'episodic' => 'Epizodno', + 'episodic_hint' => 'Ukoliko su epizode namenjene za konzumiranje bez nekog specifičnog reda. Najnovija epizoda će biti predstavljena prva u redosledu.', + 'serial' => 'Serijski', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Opis', + 'classification_section_title' => 'Klasifikacija', + 'classification_section_subtitle' => + 'Ova polja će uticati na vašu publiku i konkurenciju.', + 'language' => 'Jezik', + 'category' => 'Kategorija', + 'category_placeholder' => 'Izaberite kategoriju…', + 'other_categories' => 'Ostale kategorije', + 'parental_advisory' => [ + 'label' => 'Upozorenje za roditelje', + 'hint' => 'Da li sadrži eksplicitan sadržaj?', + 'undefined' => 'nedefinisano', + 'clean' => 'Čisto', + 'explicit' => 'Eksplicitno', + ], + 'author_section_title' => 'Autor', + 'author_section_subtitle' => 'Ko upravlja podkastom?', + 'owner_name' => 'Ime vlasnika', + 'owner_name_hint' => + 'Za administrativnu upotrebu. Vidljivo u javnom RSS feed-u.', + 'owner_email' => 'Elektronska pošta vlasnika', + 'owner_email_hint' => + 'Koristiće se na većini platforma kako bi se utvrdilo vlasništvo nad podkastom. Vidljivo javno u RSS feed-u.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Izdavač', + 'publisher_hint' => + 'Grupa odgovorna za stvaranje ove emisije. Često se misli na vlasničku kompaniju ili mrežu kojoj pripada podkast. Ovo polje se nekada naziva i \'Autor".', + 'copyright' => 'Autorsko pravo', + 'location_section_title' => 'Lokacija', + 'location_section_subtitle' => 'O kom mestu je ova epizoda?', + 'location_name' => 'Ime ili adresa lokacije', + 'location_name_hint' => 'Ovo može biti stvarno ili izmišljeno mesto', + 'monetization_section_title' => 'Monetizacija', + 'monetization_section_subtitle' => + 'Zaradi novac zahvaljujući svojoj publici.', + 'premium' => 'Premijum', + 'premium_by_default' => 'Epizode ​​se podrazumevano moraju podesiti kao premijum', + 'premium_by_default_hint' => 'Epizode ​​podkasta će podrazumevano biti označene kao premijum. I dalje možete izabrati da neke epizode, trejlere ili bonuse postavite kao javne.', + 'op3' => 'Otvoreni Podkast Prefiks Projekat (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Vrednujte svoje analitičke podatke pomoću OP3, otvorenog koda i pouzdane analitičke usluge treće strane. Delite, potvrdite i uporedite svoje analitičke podatke sa otvorenim podkast ekosistemom.', + 'op3_enable' => 'Omogućite OP3 analitičku uslugu', + 'op3_enable_hint' => 'Iz bezbednosnih razloga, analitika premijum epizoda se neće deliti sa OP3.', + 'payment_pointer' => 'Pokazivač plaćanja za Veb monetizaciju', + 'payment_pointer_hint' => + 'Ovde ćete primati novac zahvaljujući Veb monetizaciji', + 'advanced_section_title' => 'Napredni parametri', + 'advanced_section_subtitle' => + 'Ukoliko su vam potrebni RSS tagovi koje Castopod ne obrađuje, postavite ih ovde.', + 'custom_rss' => 'Posebni RSS tagovi epizode', + 'custom_rss_hint' => 'Ovo će biti ubačeno u ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Novi URL fid', + 'new_feed_url_hint' => 'Koristite ovo polje kada prelazite na drugi domen ili platformu za hostovanje podkasta. Podrazumevano, vrednost je podešena na trenutni RSS URL ako je podkast uvezen.', + 'old_feed_url' => 'Stari URL fid', + 'partnership' => 'Partnerstvo', + 'partner_id' => 'ID', + 'partner_link_url' => 'URL adresa veze', + 'partner_image_url' => 'URL adresa slike', + 'partner_id_hint' => 'Vaš partnerski ID', + 'partner_link_url_hint' => 'Generička adresa veze partnera', + 'partner_image_url_hint' => 'Generička adresa slike partnera', + 'block' => 'Podkast treba sakriti iz javnih kataloga', + 'block_hint' => + 'Prikazan ili sakriven status podkasta: ukoliko uključite ovu opciju onemogućavate prikazivanje vašeg podkasta na paltformama za slušanje podkasta kao što su Apple Podcasts, Google Podcasts i sličnim direktorijima. (Nije zagarantovano)', + 'complete' => 'Podkast više neće imati novih epizoda', + 'lock' => 'Sprečite kopiranje podkasta', + 'lock_hint' => + 'Cilj ovoga je da komunicira sa drugim podkast platformama i ne dozvoli im da povlače vaš sadržaj. Ukoliko odaberete Da, to znači da će svaki njihov pokušaj da izlistaju vaš sadržaj na svojoj platformi biti odbijen.', + 'submit_create' => 'Napravi podkast', + 'submit_edit' => 'Sačuvaj podkast', + ], + 'category_options' => [ + 'uncategorized' => 'nekategorizovano', + 'arts' => 'Umetnost', + 'business' => 'Posao', + 'comedy' => 'Komedija', + 'education' => 'Obrazovanje', + 'fiction' => 'Fikcija', + 'government' => 'Vlada', + 'health_and_fitness' => 'Zdravlje i Fitnes', + 'history' => 'Istorija', + 'kids_and_family' => 'Deca i Porodica', + 'leisure' => 'Razonoda', + 'music' => 'Muzika', + 'news' => 'Vesti', + 'religion_and_spirituality' => 'Religija i spiritualnost', + 'science' => 'Nauka', + 'society_and_culture' => 'Društvo i Kultura', + 'sports' => 'Sport', + 'technology' => 'Tehnologija', + 'true_crime' => 'Istinski zločini', + 'tv_and_film' => 'Televizija i Film', + 'books' => 'Knjige', + 'design' => 'Dizajn', + 'fashion_and_beauty' => 'Moda i Lepota', + 'food' => 'Hrana', + 'performing_arts' => 'Izvođačka umetnost', + 'visual_arts' => 'Likovna umetnost', + 'careers' => 'Karijera', + 'entrepreneurship' => 'Prednuzetništvo', + 'investing' => 'Investiranje', + 'management' => 'Upravljanje', + 'marketing' => 'Marketing', + 'non_profit' => 'Neprofitna udruženja', + 'comedy_interviews' => 'Komični intervjui', + 'improv' => 'Improvizacija', + 'stand_up' => 'Stendap komedija', + 'courses' => 'Kursevi', + 'how_to' => 'Uradi sam', + 'language_learning' => 'Učenje jezika', + 'self_improvement' => 'Samopoboljšanje', + 'comedy_fiction' => 'Komična fantastika', + 'drama' => 'Drama', + 'science_fiction' => 'Naučna Fantastika', + 'alternative_health' => 'Alternativno zdravlje', + 'fitness' => 'Fitnes', + 'medicine' => 'Medicina', + 'mental_health' => 'Mentalno zdravlje', + 'nutrition' => 'Nutricionizam', + 'sexuality' => 'Seksualnost', + 'education_for_kids' => 'Obrazovanje dece', + 'parenting' => 'Roditeljstvo', + 'pets_and_animals' => 'Ljubimci i životinje', + 'stories_for_kids' => 'Priče za decu', + 'animation_and_manga' => 'Animacija i Manga', + 'automotive' => 'Automobilizam', + 'aviation' => 'Avijacija', + 'crafts' => 'Zanati', + 'games' => 'Igre', + 'hobbies' => 'Hobiji', + 'home_and_garden' => 'Dom i bašta', + 'video_games' => 'Video igre', + 'music_commentary' => 'Komentari muzike', + 'music_history' => 'Istorija muzike', + 'music_interviews' => 'Muzički intervjui', + 'business_news' => 'Vesti iz preduzetništva', + 'daily_news' => 'Dnevne vesti', + 'entertainment_news' => 'Vesti iz zabave', + 'news_commentary' => 'Komentari vesti', + 'politics' => 'Politika', + 'sports_news' => 'Sportske vesti', + 'tech_news' => 'Tehnološke vesti', + 'buddhism' => 'Budizam', + 'christianity' => 'Hrišćanstvo', + 'hinduism' => 'Hinduizam', + 'islam' => 'Islam', + 'judaism' => 'Judeizam', + 'religion' => 'Religija', + 'spirituality' => 'Duhovnost', + 'astronomy' => 'Astronomija', + 'chemistry' => 'Hemija', + 'earth_sciences' => 'Studije zemlje', + 'life_sciences' => 'Studije života', + 'mathematics' => 'Matematika', + 'natural_sciences' => 'Prirodne nauke', + 'nature' => 'Priroda', + 'physics' => 'Fizika', + 'social_sciences' => 'Društvene nauke', + 'documentary' => 'Dokumentarni', + 'personal_journals' => 'Lični dnevnici', + 'philosophy' => 'Filozofija', + 'places_and_travel' => 'Mesta i Putovanje', + 'relationships' => 'Veze', + 'baseball' => 'Bejzbol', + 'basketball' => 'Košarka', + 'cricket' => 'Kriket', + 'fantasy_sports' => 'Fantazi sport', + 'football' => 'Američki fudbal', + 'golf' => 'Golf', + 'hockey' => 'Hokej', + 'rugby' => 'Ragbi', + 'running' => 'Trčanje', + 'soccer' => 'Fudbal', + 'swimming' => 'Plivanje', + 'tennis' => 'Tenis', + 'volleyball' => 'Odbojka', + 'wilderness' => 'Divljina', + 'wrestling' => 'Rvanje', + 'after_shows' => 'Posle emisija', + 'film_history' => 'Filmska istorija', + 'film_interviews' => 'Filmski intervjui', + 'film_reviews' => 'Filmske recenzije', + 'tv_reviews' => 'Televizijske recenzije', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Nazad na komandnu tablu podkasta', + 'post' => 'Najava vaše objave', + 'post_hint' => + "Napišite poruku kako bi ste najavili objavljivanje vašeg podkasta. Ova poruka će biti istaknuta na početnoj stranici vašeg podkasta.", + 'message_placeholder' => 'Napišite poruku…', + 'submit' => 'Objavi', + 'publication_date' => 'Datum objavljivanja', + 'publication_method' => [ + 'now' => 'Sada', + 'schedule' => 'Raspored', + ], + 'scheduled_publication_date' => 'Planiran datum objave', + 'scheduled_publication_date_hint' => + 'Možete zakazati objavu podkasta u budućnosti. Ovo polje mora biti popunjeno u YYYY-MM-DD HH:mm formatu', + 'submit_edit' => 'Uredi objavu', + 'cancel_publication' => 'Poništi objavu', + 'message_warning' => 'Niste napisali poruku za najavu objave!', + 'message_warning_hint' => 'Poruka povećava šanse za angažovanjem na društvenim mrežama, rezultirajući u većoj vidljivosti vašeg podkasta.', + 'message_warning_submit' => 'Objavi svakako', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'režim nacrta', + 'not_published' => 'Ovaj podkast nije još uvek objavljen.', + 'scheduled' => 'Ovaj podkast je zakazan za objavu {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Brisanjem podkasta obrisaće se i sve epizode, medijske datoteke, objave i analitika povezana sa njim. Ova radnja je nepovratna, nakon toga nećete više moći da ih preuzmete ili povratite.", + 'understand' => 'Razumem, želim da trajno obrišem podkast', + 'submit' => 'Obriši', + ], + 'by' => 'Od {publisher}', + 'season' => 'Sezona {seasonNumber}', + 'list_of_episodes_year' => '{year} epizoda ({episodeCount})', + 'list_of_episodes_season' => + 'Sezona {seasonNumber} epizoda ({episodeCount})', + 'no_episode' => 'Nijedna epizode nije pronađena!', + 'follow' => 'Prati', + 'followers' => '{numberOfFollowers, plural, + one {# pratilac} + other {# pratilaca} + }', + 'posts' => '{numberOfPosts, plural, + one {# objava} + other {# objave} + }', + 'activity' => 'Aktivnost', + 'episodes' => 'Epizode', + 'sponsor' => 'Sponzor', + 'funding_links' => 'Linkovi za finansiranje {podcastTitle}', + 'find_on' => 'Pronađi {podcastTitle} na', + 'listen_on' => 'Slušaj na', +]; diff --git a/modules/Admin/Language/sr-latn/PodcastNavigation.php b/modules/Admin/Language/sr-latn/PodcastNavigation.php new file mode 100644 index 00000000..5958a625 --- /dev/null +++ b/modules/Admin/Language/sr-latn/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Idite na stranu podkasta', + 'rss_feed' => 'RSS izvor', + 'dashboard' => 'Kontrolna strana podkasta', + 'podcast-view' => 'Početna stranica', + 'podcast-edit' => 'Uredi podkast', + 'podcast-persons-manage' => 'Upravljaj osobama', + 'podcast-imports' => 'Uvozi podkasta', + 'podcast-imports-sync' => 'Sinhronizuj snabdevače', + 'episodes' => 'Epizode', + 'episode-list' => 'Sve Epizode', + 'episode-create' => 'Nova epizoda', + 'analytics' => 'Analitika', + 'podcast-analytics' => 'Pregled publike', + 'podcast-analytics-webpages' => 'Poseta Veb stranici', + 'podcast-analytics-locations' => 'Lokacije', + 'podcast-analytics-unique-listeners' => 'Jedinstveni slušaoci', + 'podcast-analytics-players' => 'Plejeri', + 'podcast-analytics-listening-time' => 'Ukupno vreme slušanja', + 'podcast-analytics-time-periods' => 'Vremenski periodi', + 'monetization' => 'Monetizacija', + 'subscription-list' => 'Sve pretplate', + 'subscription-create' => 'Dodaj pretplatu', + 'contributors' => 'Saradnici', + 'contributor-list' => 'Svi saradnici', + 'contributor-add' => 'Dodaj saradnika', + 'broadcast' => 'Emitovanje', + 'platforms-podcasting' => 'Podkasting aplikacije', + 'platforms-social' => 'Društvene mreže', + 'platforms-funding' => 'Podrška', + 'podcast-monetization-other' => 'Drugo', +]; diff --git a/modules/Admin/Language/sr-latn/Settings.php b/modules/Admin/Language/sr-latn/Settings.php new file mode 100644 index 00000000..82554b3c --- /dev/null +++ b/modules/Admin/Language/sr-latn/Settings.php @@ -0,0 +1,58 @@ + 'Opšta podešavanja', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Ikonica sajta', + 'site_icon_delete' => 'Obriši ikonicu sajta', + 'site_icon_hint' => 'Ikone sajtova su ono što vidite na karticama pregledača, traci sa obeleživačima i kada dodate veb lokaciju kao prečicu na mobilnim uređajima.', + 'site_icon_helper' => 'Ikona mora biti kvadratnog oblika i minimum 512px široka i visoka.', + 'site_name' => 'Naziv veb strane', + 'site_description' => 'Opis veb strane', + 'submit' => 'Sačuvaj', + 'editSuccess' => 'Instanca je uspešno ažurirana!', + 'deleteIconSuccess' => 'Ikona veb strane je uspešno uklonjena!', + ], + 'images' => [ + 'title' => 'Slike', + 'subtitle' => 'Ovde možete regenerisati sve slike na osnovu originala koji su otpremljeni. Koristi se ako ustanovite da neke slike nedostaju. Ovaj zadatak može potrajati.', + 'regenerate' => 'Regeneriši slike', + 'regenerationSuccess' => 'Sve slike su uspešno regenerisane!', + ], + 'housekeeping' => [ + 'title' => 'Održavanje', + 'subtitle' => 'Obavlja razne poslove u održavanju. Koristite ovu funkciju ako ikada naiđete na probleme sa medijskim datotekama ili integritetom podataka. Ovi zadaci mogu potrajati.', + 'reset_counts' => 'Resetujte brojače', + 'reset_counts_helper' => 'Ova opcija će ponovo izračunati i resetovati sve podatke (broj pratilaca, objava, komentara,…).', + 'rewrite_media' => 'Ponovo upiši medijske metapodatke', + 'rewrite_media_helper' => 'Ova opcija će izbrisati sve suvišne medijske datoteke i ponovo ih kreirati (slike, audio datoteke, transkripte, poglavlja,…)', + 'rename_episodes_files' => 'Preimenuj audio datoteku epizode', + 'rename_episodes_files_hint' => 'Ova opcija će preimenovati sve audio datoteke epizoda u nasumični niz znakova. Koristite ovo ako je neka od vaših privatnih epizoda procurila jer će je to efektivno sakriti.', + 'clear_cache' => 'Obriši sav keš', + 'clear_cache_helper' => 'Ova opcija će isprazniti redis keš ili datoteke za pisanje/keširanje.', + 'run' => 'Pokreni održavanje', + 'runSuccess' => 'Održavanje je uspešno obavljeno!', + ], + 'theme' => [ + 'title' => 'Tema', + 'accent_section_title' => 'Naglašena boja', + 'accent_section_subtitle' => 'Izaberite boju da biste odredili izgled svih javnih stranica.', + 'pine' => 'Bor zelena', + 'crimson' => 'Tamnocrvena', + 'amber' => 'Ćilibar', + 'lake' => 'Jezero plava', + 'jacaranda' => 'Jakaranda ljubičasta', + 'onyx' => 'Oniks crna', + 'submit' => 'Sačuvaj', + 'setInstanceThemeSuccess' => 'Tema je uspešno ažurirana!', + ], +]; diff --git a/modules/Admin/Language/sr-latn/Soundbite.php b/modules/Admin/Language/sr-latn/Soundbite.php new file mode 100644 index 00000000..306681f9 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Zvučni isečci', + 'soundbite' => 'Zvučni isečak', + ], + 'messages' => [ + 'createSuccess' => 'Zvučni isečak je uspešno kreiran!', + 'deleteSuccess' => 'Zvučni isečak je uspešno uklonjen!', + ], + 'form' => [ + 'title' => 'Novi zvučni isečak', + 'soundbite_title' => 'Naziv zvučnog isečka', + 'start_time' => 'Počni na', + 'duration' => 'Trajanje', + 'submit' => 'Napravi zvučni isečak', + ], + 'play' => 'Reprodukuj zvučni isečak', + 'stop' => 'Zaustavi zvučni isečak', + 'create' => 'Novi zvučni isečak', + 'delete' => 'Obriši zvučni isečak', +]; diff --git a/modules/Admin/Language/sr-latn/Validation.php b/modules/Admin/Language/sr-latn/Validation.php new file mode 100644 index 00000000..d83783d4 --- /dev/null +++ b/modules/Admin/Language/sr-latn/Validation.php @@ -0,0 +1,17 @@ + + '{field} ili nije slika ili nije dovoljne dužine/visine.', + 'is_image_ratio' => + '{field} ili nije slike ili nije u pravom odnosu veličina.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/sr-latn/VideoClip.php b/modules/Admin/Language/sr-latn/VideoClip.php new file mode 100644 index 00000000..aa0d795b --- /dev/null +++ b/modules/Admin/Language/sr-latn/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video isečci', + 'status' => [ + 'label' => 'Status', + 'queued' => 'čekanje', + 'queued_hint' => 'Video isečak čeka na obradu.', + 'pending' => 'na čekanju', + 'pending_hint' => 'Video isečak će uskoro biti napravljen.', + 'running' => 'u toku', + 'running_hint' => 'Video isečak se pravi.', + 'failed' => 'nije uspеlo', + 'failed_hint' => 'Pravljenje video isečka nije uspelo: greška u skripti.', + 'passed' => 'prošlo', + 'passed_hint' => 'Video isečak je uspešno napravljen!', + ], + 'clip' => 'Isečak', + 'duration' => 'Trajanje posla', + ], + 'title' => 'Video Isečak: {videoClipLabel}', + 'download_clip' => 'Preuzmi isečak', + 'create' => 'Novi video isečak', + 'go_to_page' => 'Idi na stranicu isečka', + 'retry' => 'Ponovo pokušaj da napraviš isečak', + 'delete' => 'Obriši isečak', + 'logs' => 'Katalog poslova', + 'messages' => [ + 'alreadyExistingError' => 'Video isečak koji pokušavate da napravite već postoji!', + 'addToQueueSuccess' => 'Video isečak je dodat u katalog poslova, čeka da bude napravljen!', + 'deleteSuccess' => 'Video isečak je uspešno uklonjen!', + ], + 'format' => [ + 'landscape' => 'Položeno', + 'portrait' => 'Uspravno', + 'squared' => 'Kvadratno', + ], + 'form' => [ + 'title' => 'Novi video isečak', + 'params_section_title' => 'Parametri video isečka', + 'clip_title' => 'Naziv isečka', + 'format' => [ + 'label' => 'Odaberite format', + 'landscape_hint' => 'U 16:9 formatu, položeni video klipovi su odlični za platforme kao što su PeerTube, YouTube i Vimeo.', + 'portrait_hint' => 'U 9:16 formatu, uspravni video isečci su odlični za TikTok, YouTube shorts i Instagram stories.', + 'squared_hint' => 'U 1:1 formatu, kvadratni video isečci su odlični za Mastodon, Facebook, Twitter i LinkedIn.', + ], + 'theme' => 'Odaberite temu', + 'start_time' => 'Počni na', + 'duration' => 'Trajanje', + 'trim_start' => 'Početak isečka', + 'trim_end' => 'Kraj isečka', + 'submit' => 'Napravi video isečak', + ], + 'requirements' => [ + 'title' => 'Nedostaje polje', + 'missing' => 'Niste popunili sva polja. Potrudite se da ubacite sve što je potrebno kako bi ste napravili video za ovu epizodu!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Datoteka transkripta (.srt)', + ], +]; diff --git a/modules/Admin/Language/sv/AboutCastopod.php b/modules/Admin/Language/sv/AboutCastopod.php new file mode 100644 index 00000000..f9707cbe --- /dev/null +++ b/modules/Admin/Language/sv/AboutCastopod.php @@ -0,0 +1,22 @@ + 'Om Castopod', + 'host_name' => 'Värdnamn', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operativsystem', + 'languages' => 'Språk', + 'update_database' => 'Uppdatera databas', + 'messages' => [ + 'databaseUpdateSuccess' => 'Databasen är uppdaterad!', + ], +]; diff --git a/modules/Admin/Language/sv/Breadcrumb.php b/modules/Admin/Language/sv/Breadcrumb.php new file mode 100644 index 00000000..7acad68e --- /dev/null +++ b/modules/Admin/Language/sv/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Hem', + 'podcasts' => 'podcasts', + 'episodes' => 'avsnitt', + 'subscriptions' => 'prenumerationer', + 'contributors' => 'bidragsgivare', + 'pages' => 'sidor', + 'settings' => 'inställningar', + 'theme' => 'tema', + 'about' => 'om', + 'add' => 'lägg till', + 'new' => 'ny', + 'edit' => 'redigera', + 'persons' => 'personer', + 'publish' => 'publicera', + 'publish-edit' => 'redigera publikation', + 'publish-date-edit' => 'redigera publiceringsdatum', + 'unpublish' => 'avpublicera', + 'delete' => 'radera', + 'remove' => 'ta bort', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'användare', + 'my-account' => 'mitt konto', + 'change-password' => 'ändra lösenord', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'plattformar', + 'social' => 'sociala nätverk', + 'funding' => 'finansiering', + 'monetization-other' => 'other monetization', + 'analytics' => 'analys', + 'locations' => 'platser', + 'webpages' => 'webbplatser', + 'unique-listeners' => 'unika lyssnare', + 'players' => 'spelare', + 'listening-time' => 'lyssningstid', + 'time-periods' => 'tidsperiod', + 'soundbites' => 'ljudklipp', + 'video-clips' => 'videoklipp', + 'embed' => 'inbäddad spelare', + 'notifications' => 'aviseringar', + 'suspend' => 'suspendera', +]; diff --git a/modules/Admin/Language/sv/Charts.php b/modules/Admin/Language/sv/Charts.php new file mode 100644 index 00000000..868b40fd --- /dev/null +++ b/modules/Admin/Language/sv/Charts.php @@ -0,0 +1,41 @@ + 'Avsnitt nedladdningar via tjänst (under den senaste veckan)', + 'by_player_weekly' => 'Nedladdningar av avsnitt via spelare (under den senaste veckan)', + 'by_player_yearly' => 'Nedladdningar av avsnitt via spelare (under det gångna året)', + 'by_device_weekly' => 'Avsnitt nedladdningar per enhet (föregående veckan)', + 'by_os_weekly' => 'Avsnitt nedladdningar av O.S. (för den föregående veckan)', + 'podcast_by_region' => 'Nedladdningar av avsnitt efter region (under den föregående veckan)', + 'unique_daily_listeners' => 'Dagliga unika lyssnare', + 'unique_monthly_listeners' => 'Unika lyssnare varje månad', + 'by_browser' => 'Webbsidor användning av webbläsare (under den föregående veckan)', + 'podcast_by_day' => 'Avsnitt dagliga nedladdningar', + 'podcast_by_month' => 'Månatliga nedladdningar av avsnitt', + 'episode_by_day' => 'Avsnitt dagliga nedladdningar (första 60 dagar)', + 'episode_by_month' => 'Månatliga nedladdningar av avsnitt', + 'episodes_by_day' => + '5 senaste avsnitt nedladdningar (under sina första 60 dagar)', + 'by_country_weekly' => 'Nedladdningar av avsnitt per land (under den föregående veckan)', + 'by_country_yearly' => 'Nedladdningar av avsnitt per land (för föregående året)', + 'by_domain_weekly' => 'Webbsidor besök per källa (under föregående veckan)', + 'by_domain_yearly' => 'Webbsidor besök per källa (för det gångna året)', + 'by_entry_page' => 'Webbsidor besök via startsida (under den föregående veckan)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daglig kumulativ lyssningstid', + 'monthly_listening_time' => 'Månatlig kumulativ lyssningstid', + 'by_weekday' => 'Efter veckodag (för de senaste 60 dagarna)', + 'by_hour' => 'Via tiden på dagen (de senaste 60 dagarna)', + 'podcast_by_bandwidth' => 'Dagligen använd bandbredd (i MB)', + 'total_storage_by_month' => 'Månadslagring (i MB)', + 'total_bandwidth_by_month' => 'Månatlig använd bandbredd (i MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/sv/Common.php b/modules/Admin/Language/sv/Common.php new file mode 100644 index 00000000..465f8c4c --- /dev/null +++ b/modules/Admin/Language/sv/Common.php @@ -0,0 +1,52 @@ + 'Ja', + 'no' => 'Nej', + 'cancel' => 'Avbryt', + 'optional' => 'Valfritt', + 'more' => 'Mer', + 'no_data' => 'Ingen data hittades!', + 'close' => 'Stäng', + 'edit' => 'Redigera', + 'copy' => 'Kopiera', + 'copied' => 'Kopierad!', + 'home' => 'Hem', + 'explicit' => 'Uteslutande', + 'powered_by' => 'Drivs av {castopod}', + 'actions' => 'Åtgärder', + 'pageInfo' => 'Sida {currentPage} av {pageCount}', + 'go_back' => 'Gå tillbaka', + 'forms' => [ + 'editor' => [ + 'write' => 'Skriv', + 'preview' => 'Förhandsgranska', + 'help' => 'Drivs av markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Tryck för att välja', + 'loadingText' => 'Laddar…', + 'noResultsText' => 'Hittade inga resultat', + 'noChoicesText' => 'Inga val att välja mellan', + 'maxItemText' => 'Kan inte lägga till fler objekt', + ], + 'upload_file' => 'Ladda upp en fil', + 'remote_url' => 'Fjärr URL', + 'save' => 'Spara', + ], + 'play_episode_button' => [ + 'play' => 'Spela', + 'playing' => 'Spelar', + ], + 'size_limit' => 'Storleksgräns: {0}.', + 'choose_interact' => 'Välj hur du vill interagera', + 'view' => 'Visa', +]; diff --git a/modules/Admin/Language/sv/Countries.php b/modules/Admin/Language/sv/Countries.php new file mode 100644 index 00000000..1aed3bb0 --- /dev/null +++ b/modules/Admin/Language/sv/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'Förenade Arabemiraten', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua och Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albanien', + 'AM' => 'Armenien', + 'AO' => 'Angola', + 'AQ' => 'Antarktis', + 'AR' => 'Argentina', + 'AS' => 'Amerikanska Samoaöarna', + 'AT' => 'Österrike', + 'AU' => 'Australien', + 'AW' => 'Aruba', + 'AX' => 'Åland', + 'AZ' => 'Azerbajdzjan', + 'BA' => 'Bosnien och Hercegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgien', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgarien', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia', + 'BQ' => 'Bonaire', + 'BR' => 'Brasilien', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvetön', + 'BW' => 'Botswana', + 'BY' => 'Vitryssland', + 'BZ' => 'Belize', + 'CA' => 'Kanada', + 'CC' => 'Kokosöarna', + 'CD' => 'Kongo, Demokratiska republiken Kongo', + 'CF' => 'Centralafrikanska republiken', + 'CG' => 'Kongo', + 'CH' => 'Schweiz', + 'CI' => "Elfenbenskusten", + 'CK' => 'Cooköarna', + 'CL' => 'Chile', + 'CM' => 'Kamerun', + 'CN' => 'Kina', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Kuba', + 'CV' => 'Kap Verde', + 'CW' => 'Curacao', + 'CX' => 'Julön', + 'CY' => 'Cypern', + 'CZ' => 'Tjeckien', + 'DE' => 'Tyskland', + 'DJ' => 'Djibouti', + 'DK' => 'Danmark', + 'DM' => 'Dominica', + 'DO' => 'Dominikanska republiken', + 'DZ' => 'Algeriet', + 'EC' => 'Ecuador', + 'EE' => 'Estland', + 'EG' => 'Egypten', + 'EH' => 'Västsahara', + 'ER' => 'Eritrea', + 'ES' => 'Spanien', + 'ET' => 'Etiopien', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falklandsöarna (Malvinas)', + 'FM' => 'Mikronesien, Federerade Stater', + 'FO' => 'Färöarna', + 'FR' => 'Frankrike', + 'GA' => 'Gabon', + 'GB' => 'Storbritannien', + 'GD' => 'Grenada', + 'GE' => 'Georgien', + 'GF' => 'Franska Guyana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Grönland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Grekland', + 'GS' => 'Sydgeorgien och Sydsandwichöarna', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hongkong', + 'HM' => 'Heard Island och McDonaldsöarna', + 'HN' => 'Honduras', + 'HR' => 'Kroatien', + 'HT' => 'Haiti', + 'HU' => 'Ungern', + 'ID' => 'Indonesien', + 'IE' => 'Irland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'Indien', + 'IO' => 'Brittiska territoriet i Indiska oceanen', + 'IQ' => 'Irak', + 'IR' => 'Iran, Islamiska republiken av', + 'IS' => 'Island', + 'IT' => 'Italien', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordanien', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Kambodja', + 'KI' => 'Kiribati', + 'KM' => 'Komorerna', + 'KN' => 'Saint Kitts och Nevis', + 'KP' => "Nordkorea", + 'KR' => 'Sydkorea', + 'KW' => 'Kuwait', + 'KY' => 'Caymanöarna', + 'KZ' => 'Kazakstan', + 'LA' => "Laos", + 'LB' => 'Libanon', + 'LC' => 'Sankt Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberien', + 'LS' => 'Lesotho', + 'LT' => 'Litauen', + 'LU' => 'Luxembourg', + 'LV' => 'Lettland', + 'LY' => 'Libyen', + 'MA' => 'Marocko', + 'MC' => 'Monaco', + 'MD' => 'Moldavien', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin', + 'MG' => 'Madagaskar', + 'MH' => 'Marshallöarna', + 'MK' => 'Makedonien', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongoliet', + 'MO' => 'Macao', + 'MP' => 'Nordmarianerna', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldiverna', + 'MW' => 'Malawi', + 'MX' => 'Mexiko', + 'MY' => 'Malaysia', + 'MZ' => 'Moçambique', + 'N/A' => 'Ej tillämplig (lokal IP…)', + 'NA' => 'Namibia', + 'NC' => 'Nya Kaledonien', + 'NE' => 'Niger', + 'NF' => 'Norfolkön', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Nederländerna', + 'NO' => 'Norge', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'Nya Zeeland', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'Franska Polynesien', + 'PG' => 'Papua Nya Guinea', + 'PH' => 'Filippinerna', + 'PK' => 'Pakistan', + 'PL' => 'Polen', + 'PM' => 'Saint Pierre och Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestina', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Rumänien', + 'RS' => 'Serbien', + 'RU' => 'Ryssland', + 'RW' => 'Rwanda', + 'SA' => 'Saudiarabien', + 'SB' => 'Salomonöarna', + 'SC' => 'Seychellerna', + 'SD' => 'Sudan', + 'SE' => 'Sverige', + 'SG' => 'Singapore', + 'SH' => 'Sankta Helena, Ascension och Tristan da Cunha', + 'SI' => 'Slovenien', + 'SJ' => 'Svalbard', + 'SK' => 'Slovakien', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Surinam', + 'SS' => 'Sydsudan', + 'ST' => 'Sao Tome och Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (nederländska delen)', + 'SY' => 'Syrien', + 'SZ' => 'Swaziland', + 'TC' => 'Turks- och Caicosöarna', + 'TD' => 'Tchad', + 'TF' => 'Franska sydterritorierna', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelauöarna', + 'TL' => 'Östtimor', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisien', + 'TO' => 'Tonga', + 'TR' => 'Turkiet', + 'TT' => 'Trinidad och Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania', + 'UA' => 'Ukraina', + 'UG' => 'Uganda', + 'UM' => 'Förenta staternas mindre öar i Oceanien och Västindien', + 'US' => 'USA', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Vatikanstaten', + 'VC' => 'Saint Vincent och Grenadinerna', + 'VE' => 'Venezuela', + 'VG' => 'Brittiska Jungfruöarna', + 'VI' => 'Amerikanska Jungfruöarna.', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis- och Futunaöarna', + 'WS' => 'Samoa', + 'YE' => 'Jemen', + 'YT' => 'Mayotte', + 'ZA' => 'Sydafrika', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/sv/Dashboard.php b/modules/Admin/Language/sv/Dashboard.php new file mode 100644 index 00000000..cf127945 --- /dev/null +++ b/modules/Admin/Language/sv/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin kontrollpanel', + 'welcome_message' => 'Välkommen till adminområdet!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'Ingen publicerad podcast', + 'last_published' => 'Senast publicerad den {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Avsnitt', + 'not_found' => 'Inga publicerade avsnitt', + 'last_published' => 'Senast publicerad den {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Lagring', + 'subtitle' => '{totalUploaded} av {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/sv/Episode.php b/modules/Admin/Language/sv/Episode.php new file mode 100644 index 00000000..38c7b20c --- /dev/null +++ b/modules/Admin/Language/sv/Episode.php @@ -0,0 +1,225 @@ + 'Säsong {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Avsnitt {episodeNumber}', + 'number_abbr' => 'Av. {episodeNumber}', + 'season_episode' => 'Säsong {seasonNumber} avsnitt {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}A{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# kommentar} + other {# kommentarer} + }', + 'all_podcast_episodes' => 'Alla podcast avsnitt', + 'back_to_podcast' => 'Gå tillbaka till podcasten', + 'edit' => 'Redigera', + 'preview' => 'Preview', + 'publish' => 'Publicera', + 'publish_edit' => 'Redigera publikation', + 'publish_date_edit' => 'Redigera publiceringsdatum', + 'unpublish' => 'Avpublicera', + 'publish_error' => 'Avsnittet är redan publicerat.', + 'publish_edit_error' => 'Avsnittet är redan publicerat.', + 'publish_cancel_error' => 'Avsnittet är redan publicerat.', + 'publish_date_edit_error' => 'Avsnittet har inte publicerats ännu, du kan inte redigera dess publiceringsdatum.', + 'publish_date_edit_future_error' => 'Avsnittets publiceringsdatum kan bara ställas in till ett tidigare datum! Om du vill boka om det, avpublicera det först.', + 'publish_date_edit_success' => 'Avsnittets publiceringsdatum har uppdaterats!', + 'unpublish_error' => 'Avsnittet är inte publicerat.', + 'delete' => 'Radera', + 'go_to_page' => 'Gå till sida', + 'create' => 'Lägg till ett avsnitt', + 'publication_status' => [ + 'published' => 'Publicerad', + 'with_podcast' => 'Publicerad', + 'scheduled' => 'Schemalagd', + 'not_published' => 'Ej publicerat', + ], + 'with_podcast_hint' => 'Publiceras samtidigt som podcasten', + 'list' => [ + 'search' => [ + 'placeholder' => 'Sök efter ett avsnitt', + 'clear' => 'Rensa sökning', + 'submit' => 'Sök', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# avsnitt} + other {# avsnitt} + }', + 'episode' => 'Avsnitt', + 'visibility' => 'Synlighet', + 'downloads' => 'Downloads', + 'comments' => 'Kommentarer', + 'actions' => 'Åtgärder', + ], + 'messages' => [ + 'createSuccess' => 'Avsnittet har skapats!', + 'editSuccess' => 'Avsnittet har uppdaterats!', + 'publishSuccess' => '{publication_status, select, + published {Avsnittet har publicerats!} + scheduled {Avsnittspubliceringen har planerats!} + with_podcast {Detta avsnitt kommer att publiceras samtidigt som podcasten.} + other {Detta avsnitt är inte publicerad.} + }', + 'publishCancelSuccess' => 'Avsnitt publicering har avbrutits!', + 'unpublishBeforeDeleteTip' => 'Du måste avpublicera avsnittet innan du tar bort det.', + 'scheduleDateError' => 'Schemaläggningsdatum måste anges!', + 'deletePublishedEpisodeError' => 'Avpublicera avsnittet innan du tar bort det.', + 'deleteSuccess' => 'Avsnittet har tagits bort!', + 'deleteError' => 'Misslyckades att ta bort avsnitt {type, select, + transcript {transcript} + chapters {kapitel} + image {omslag} + audio {ljud} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'Ett avsnitt med den valda slug finns redan.', + ], + 'form' => [ + 'file_size_error' => + 'Din filstorlek är för stor! Max storlek är {0}. Öka värdena `memory_limit`, `upload_max_filesize` och `post_max_size` i din php-konfigurationsfil och starta sedan om din webbserver för att ladda upp filen.', + 'audio_file' => 'Ljudfil', + 'audio_file_hint' => 'Välj en. mp3 eller . m4a ljudfil.', + 'info_section_title' => 'Avsnitt information', + 'cover' => 'Avsnitt omslag', + 'cover_hint' => + 'Om du inte sätter ett omslag kommer podcast-omslaget att användas istället.', + 'cover_size_hint' => 'Omslaget måste vara fyrkantigt och minst 1400px brett och högt.', + 'title' => 'Rubrik', + 'title_hint' => + 'Bör innehålla ett tydligt och koncist avsnittsnamn. Ange inte avsnitt eller säsongsnummer här.', + 'permalink' => 'Permalänk', + 'season_number' => 'Säsong', + 'episode_number' => 'Avsnitt', + 'type' => [ + 'label' => 'Typ', + 'full' => 'Full', + 'full_hint' => 'Komplett innehåll (avsnittet)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Kort, PR-del av innehåll som representerar en förhandsvisning av den aktuella serien', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra innehåll för showen (till exempel bakom scenens info eller intervjuer med cast) eller korspremiellt innehåll för en annan show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Avsnitt måste endast vara tillgängligt för premiumprenumeranter', + 'parental_advisory' => [ + 'label' => 'Föräldrarådgivande', + 'hint' => 'Innehåller avsnittet olämpligt innehåll?', + 'undefined' => 'odefinierad', + 'clean' => 'Ren', + 'explicit' => 'Uteslutande', + ], + 'show_notes_section_title' => 'Visa anteckningar', + 'show_notes_section_subtitle' => + 'Upp till 4000 tecken, var tydlig och koncis. Visa anteckningar hjälper potentiella lyssnare att hitta avsnittet.', + 'description' => 'Beskrivning', + 'description_footer' => 'Beskrivning sidfot', + 'description_footer_hint' => + 'Denna text läggs till i slutet av varje avsnitt beskrivning, det är ett bra ställe att skriva in dina sociala länkar till exempel.', + 'additional_files_section_title' => 'Ytterligare filer', + 'additional_files_section_subtitle' => + 'Dessa filer kan användas av andra plattformar för att ge bättre upplevelse till din publik. Se {podcastNamespaceLink} för mer information.', + 'location_section_title' => 'Plats', + 'location_section_subtitle' => 'Vilken plats handlar detta avsnitt om?', + 'location_name' => 'Platsnamn eller adress', + 'location_name_hint' => 'Detta kan vara en verklig eller fiktiv plats', + 'transcript' => 'Avskrift (undertexter / undertexter)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Ladda ner avskrift', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Fjärr-URL för avskrift', + 'transcript_file_delete' => 'Ta bort avskrift', + 'chapters' => 'Kapitel', + 'chapters_hint' => 'Filen måste vara i JSON Kapitelformat.', + 'chapters_download' => 'Ladda ner kapitel', + 'chapters_file' => 'Kapitel fil', + 'chapters_remote_url' => 'Fjärr-URL för kapitelfil', + 'chapters_file_delete' => 'Ta bort kapitelfil', + 'advanced_section_title' => 'Avancerade parametrar', + 'advanced_section_subtitle' => + 'Om du behöver RSS-taggar som Castopod inte hanterar, ställ in dem här.', + 'custom_rss' => 'Anpassade RSS-taggar för avsnittet', + 'custom_rss_hint' => 'Detta kommer att injiceras inom item taggen.', + 'block' => 'Avsnitt bör döljas från offentliga kataloger', + 'block_hint' => + 'Avsnitten visa eller dölja status: växla detta hindrar avsnitten från att visas i Apple Podcasts, Google Podcasts, och alla tredjepartsappar som drar program från dessa kataloger. (Inte garanterat)', + 'submit_create' => 'Skapa avsnitt', + 'submit_edit' => 'Spara avsnitt', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Tillbaka till avsnittets instrumentpanel', + 'post' => 'Ditt meddelande inlägg', + 'post_hint' => + "Skriv ett meddelande för att meddela publiceringen av ditt avsnitt. Meddelandet kommer att sändas till alla dina följare i fediverse och presenteras på din podcasts hemsida.", + 'message_placeholder' => 'Skriv ditt meddelande…', + 'publication_date' => 'Publiceringsdatum', + 'publication_method' => [ + 'now' => 'Nu', + 'schedule' => 'Schemalägg', + 'with_podcast' => 'Publicera tillsammans med podcast', + ], + 'scheduled_publication_date' => 'Planerat publiceringsdatum', + 'scheduled_publication_date_clear' => 'Rensa publiceringsdatum', + 'scheduled_publication_date_hint' => + 'Du kan schemalägga avsnittet genom att ställa in ett framtida publiceringsdatum. Detta fält måste formateras som ÅÅÅ-MM-DD HH:mm', + 'submit' => 'Publicera', + 'submit_edit' => 'Redigera publikation', + 'cancel_publication' => 'Avbryt publicering', + 'message_warning' => 'Du skrev inte ett meddelande för ditt tillkännagivande!', + 'message_warning_hint' => 'Att ha ett meddelande ökar socialt engagemang, vilket resulterar i en bättre synlighet för ditt avsnitt.', + 'message_warning_submit' => 'Publicera ändå', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'Nytt publiceringsdatum', + 'new_publication_date_hint' => 'Måste vara inställd till ett tidigare datum.', + 'submit' => 'Redigera publiceringsdatum', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Avpublicera avsnittet kommer att ta bort alla kommentarer och inlägg som är associerade med det och ta bort det från podcastens RSS-flöde.", + 'understand' => 'Jag förstår, jag vill avpublicera avsnittet', + 'submit' => 'Avpublicera', + ], + 'delete_form' => [ + 'disclaimer' => + "Borttagning av avsnittet kommer att ta bort alla mediefiler, kommentarer, videoklipp och ljudfiler som är associerade med det.", + 'understand' => 'Jag förstår, Jag vill ta bort avsnittet', + 'submit' => 'Radera', + ], + 'embed' => [ + 'title' => 'Inbäddad spelare', + 'label' => + 'Välj ett tema färg, kopiera den inbäddade spelaren till urklipp, sedan klistra in den på din webbplats.', + 'clipboard_iframe' => 'Kopiera inbäddbar spelare till urklipp', + 'clipboard_url' => 'Kopiera adress till urklipp', + 'dark' => 'Mörk', + 'dark-transparent' => 'Mörk transparent', + 'light' => 'Ljust', + 'light-transparent' => 'Ljus transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/sv/EpisodeNavigation.php b/modules/Admin/Language/sv/EpisodeNavigation.php new file mode 100644 index 00000000..59f92a52 --- /dev/null +++ b/modules/Admin/Language/sv/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'Visa avsnittssida', + 'dashboard' => 'Avsnittets instrumentpanel', + 'episode-view' => 'Hem', + 'episode-edit' => 'Redigera avsnitt', + 'episode-persons-manage' => 'Hantera personer', + 'embed-add' => 'Inbäddad spelare', + 'clips' => 'Klipp', + 'video-clips-list' => 'Videoklipp', + 'video-clips-create' => 'Nytt videoklipp', + 'soundbites-list' => 'Ljudklipp', + 'soundbites-create' => 'Ny ljudbit', +]; diff --git a/modules/Admin/Language/sv/Fediverse.php b/modules/Admin/Language/sv/Fediverse.php new file mode 100644 index 00000000..18a1b209 --- /dev/null +++ b/modules/Admin/Language/sv/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'Det gick inte att hitta kontot!', + 'blockActorSuccess' => '{actor} har blockerats!', + 'unblockActorSuccess' => 'Aktören har blivit avblockerad!', + 'blockDomainSuccess' => '{domain} har blockerats!', + 'unblockDomainSuccess' => '{domain} har blivit avblockerad!', + ], + 'blocked_actors' => 'Blockerade konton', + 'blocked_domains' => 'Blockerade domäner', + 'block_lists_form' => [ + 'handle' => 'Hantera konto', + 'handle_hint' => 'Skriv in @användarnamn@domänkonto.', + 'domain' => 'Domännamn', + 'submit' => 'Blockera!', + ], + 'list' => [ + 'actor' => 'Konto', + 'domain' => 'Domännamn', + 'unblock' => 'Avblockera', + ], +]; diff --git a/modules/Admin/Language/sv/Home.php b/modules/Admin/Language/sv/Home.php new file mode 100644 index 00000000..493b5d18 --- /dev/null +++ b/modules/Admin/Language/sv/Home.php @@ -0,0 +1,14 @@ + 'Alla podcasts', + 'no_podcast' => 'Ingen podcast hittades', +]; diff --git a/modules/Admin/Language/sv/Install.php b/modules/Admin/Language/sv/Install.php new file mode 100644 index 00000000..9e7de812 --- /dev/null +++ b/modules/Admin/Language/sv/Install.php @@ -0,0 +1,61 @@ + 'Manuell konfiguration', + 'manual_config_subtitle' => + 'Skapa en \'.env\' fil med dina inställningar och uppdatera sidan för att fortsätta installationen.', + 'form' => [ + 'instance_config' => 'Konfiguration av instans', + 'hostname' => 'Servernamn', + 'media_base_url' => 'Bas-URL för media', + 'media_base_url_hint' => + 'Om du använder en CDN och/eller en extern analystjänst kan du ställa in dem här.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'Rutten för att komma åt adminområdet (t.ex. https://example.com/cp-admin). Det är som standard inställt som cp-admin, vi rekommenderar att du ändrar det av säkerhetsskäl.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'Rutten för att komma åt autentiseringssidorna (t.ex. https://example.com/cp-auth). Den är som standard inställd som cp-auth, vi rekommenderar att du ändrar den av säkerhetsskäl.', + 'database_config' => 'Databas konfiguration', + 'database_config_hint' => + 'Castopod måste ansluta till din MySQL (eller MariaDB) databas. Om du inte har dessa nödvändiga uppgifter, kontakta din serveradministratör.', + 'db_hostname' => 'Databasens värdnamn', + 'db_name' => 'Databasnamn', + 'db_username' => 'Användarnamn till databasen', + 'db_password' => 'Databasens lösenord', + 'db_prefix' => 'Databas prefix', + 'db_prefix_hint' => + "Prefixet för Castopod tabellnamn, lämna som om du inte vet vad det betyder.", + 'cache_config' => 'Cache-konfiguration', + 'cache_config_hint' => + 'Välj önskad cachehanterare. Lämna det som standardvärde om du inte har någon aning om vad det innebär.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'Fil', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Nästa', + 'submit' => 'Slutför installationen', + 'create_superadmin' => 'Skapa ditt superadministratörskonto', + 'email' => 'Epost', + 'username' => 'Användarnamn', + 'password' => 'Lösenord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ditt superadministratörskonto har skapats. Logga in för att starta podcasting!', + 'databaseConnectError' => + 'Castopod kunde inte ansluta till din databas. Redigera din databaskonfiguration och försök igen.', + 'writeError' => + "Kunde inte skapa/skriva `.env`-filen. Du måste skapa den manuellt genom att följa filmallen `.env.exempel` i Castopod-paketet.", + ], +]; diff --git a/modules/Admin/Language/sv/Navigation.php b/modules/Admin/Language/sv/Navigation.php new file mode 100644 index 00000000..4e710a45 --- /dev/null +++ b/modules/Admin/Language/sv/Navigation.php @@ -0,0 +1,44 @@ + 'Växla sidofält', + 'go_to_website' => 'Gå till webbsidan', + 'go_to_admin' => 'Gå till admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Översiktspanel', + 'admin' => 'Hem', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'Alla podcasts', + 'podcast-create' => 'Ny podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Personer', + 'person-list' => 'Alla personer', + 'person-create' => 'Ny person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blockerade konton', + 'fediverse-blocked-domains' => 'Blockerade domäner', + 'users' => 'Användare', + 'user-list' => 'Alla användare', + 'user-create' => 'Ny användare', + 'pages' => 'Sidor', + 'page-list' => 'Alla sidor', + 'page-create' => 'Ny sida', + 'settings' => 'Inställningar', + 'settings-general' => 'Allmänt', + 'settings-theme' => 'Tema', + 'admin-about' => 'Om', + 'account' => [ + 'my-account' => 'Mitt konto', + 'change-password' => 'Ändra lösenord', + 'logout' => 'Logga ut', + ], +]; diff --git a/modules/Admin/Language/sv/Notifications.php b/modules/Admin/Language/sv/Notifications.php new file mode 100644 index 00000000..cacbb79a --- /dev/null +++ b/modules/Admin/Language/sv/Notifications.php @@ -0,0 +1,19 @@ + 'Aviseringar', + 'reply' => '{actor_username} svarade på ditt inlägg', + 'favourite' => '{actor_username} favoriterade ditt inlägg', + 'reblog' => '{actor_username} delade ditt inlägg', + 'follow' => '{actor_username} började följa dig', + 'no_notifications' => 'Inga aviseringar', + 'mark_all_as_read' => 'Markera alla som lästa', +]; diff --git a/modules/Admin/Language/sv/Page.php b/modules/Admin/Language/sv/Page.php new file mode 100644 index 00000000..89f48754 --- /dev/null +++ b/modules/Admin/Language/sv/Page.php @@ -0,0 +1,30 @@ + 'Tillbaka till startsidan', + 'page' => 'Sida', + 'all_pages' => 'Alla sidor', + 'create' => 'Ny sida', + 'go_to_page' => 'Gå till sida', + 'edit' => 'Redigera sida', + 'delete' => 'Ta bort sida', + 'form' => [ + 'title' => 'Rubrik', + 'permalink' => 'Permalänk', + 'content' => 'Innehåll', + 'submit_create' => 'Skapa sida', + 'submit_edit' => 'Spara', + ], + 'messages' => [ + 'createSuccess' => 'Sidan ”{pageTitle}” skapades framgångsrikt!', + 'editSuccess' => 'Sidan har uppdaterats!', + ], +]; diff --git a/modules/Admin/Language/sv/Pager.php b/modules/Admin/Language/sv/Pager.php new file mode 100644 index 00000000..32a18e90 --- /dev/null +++ b/modules/Admin/Language/sv/Pager.php @@ -0,0 +1,21 @@ + 'Sidnavigering', + 'first' => 'Första', + 'previous' => 'Föregående', + 'next' => 'Nästa', + 'last' => 'Sista', + 'older' => 'Äldre', + 'newer' => 'Nyare', + 'invalidTemplate' => '{0} är inte en giltig sidmall.', + 'invalidPaginationGroup' => '{0} är inte en giltig sidnumreringsgrupp.', +]; diff --git a/modules/Admin/Language/sv/Person.php b/modules/Admin/Language/sv/Person.php new file mode 100644 index 00000000..f5007527 --- /dev/null +++ b/modules/Admin/Language/sv/Person.php @@ -0,0 +1,65 @@ + 'Personer', + 'all_persons' => 'Alla personer', + 'no_person' => 'Ingen hittades!', + 'create' => 'Skapa en person', + 'view' => 'Visa person', + 'edit' => 'Redigera person', + 'delete' => 'Ta bort person', + 'messages' => [ + 'createSuccess' => 'Person har skapats framgångsrikt!', + 'editSuccess' => 'Person har uppdaterats!', + 'deleteSuccess' => 'Person har tagits bort!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar måste vara kvadratisk och minst 400px bred och hög.', + 'full_name' => 'Fullständigt namn', + 'full_name_hint' => 'Detta är personens fullständiga namn eller alias.', + 'unique_name' => 'Unikt namn', + 'unique_name_hint' => 'Används för URL: er', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url till en relevant resurs av information om personen, såsom en hemsida eller en tredje parts profilplattform.', + 'submit_create' => 'Skapa person', + 'submit_edit' => 'Spara person', + ], + 'podcast_form' => [ + 'title' => 'Hantera personer', + 'add_section_title' => 'Lägg till personer till denna podcast', + 'add_section_subtitle' => 'Du kan välja flera personer och roller.', + 'persons' => 'Personer', + 'persons_hint' => + 'Du kan välja en eller flera personer med samma roller. Du måste skapa personerna först.', + 'roles' => 'Roller', + 'roles_hint' => + 'Du kan välja ingen, en eller flera roller för en person.', + 'submit_add' => 'Lägg till person(er)', + 'remove' => 'Ta bort', + ], + 'episode_form' => [ + 'title' => 'Hantera personer', + 'add_section_title' => 'Lägg till personer till detta avsnitt', + 'add_section_subtitle' => 'Du kan välja flera personer och roller.', + 'persons' => 'Personer', + 'persons_hint' => + 'Du kan välja en eller flera personer med samma roller. Du måste skapa personerna först.', + 'roles' => 'Roller', + 'roles_hint' => + 'Du kan välja ingen, en eller flera roller för en person.', + 'submit_add' => 'Lägg till person(er)', + 'remove' => 'Ta bort', + ], + 'credits' => 'Tack till', +]; diff --git a/modules/Admin/Language/sv/Platforms.php b/modules/Admin/Language/sv/Platforms.php new file mode 100644 index 00000000..40eab4f8 --- /dev/null +++ b/modules/Admin/Language/sv/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Gå till {platformName} webbplats', + 'register' => 'Register', + 'submit_url' => 'Skicka din podcast den {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Visa på podcastens hemsida?', + 'on_embed' => 'Visa på inbäddbar spelare?', + 'remove' => 'Ta bort {platformName}', + 'submit' => 'Spara', + 'messages' => [ + 'updateSuccess' => 'Plattformslänkarna har uppdaterats!', + 'removeLinkSuccess' => 'Plattformslänken har tagits bort.', + 'removeLinkError' => + 'Plattformslänken kunde inte tas bort. Försök igen.', + ], + 'description' => [ + 'podcasting' => 'Podcast ID på denna plattform', + 'social' => 'Den podcast konto ID på denna plattform', + 'funding' => 'Ring till åtgärdsmeddelande', + ], +]; diff --git a/modules/Admin/Language/sv/Podcast.php b/modules/Admin/Language/sv/Podcast.php new file mode 100644 index 00000000..7fda701b --- /dev/null +++ b/modules/Admin/Language/sv/Podcast.php @@ -0,0 +1,330 @@ + 'Alla podcasts', + 'no_podcast' => 'Ingen podcast hittades!', + 'create' => 'Skapa podcast', + 'import' => 'Importera podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'Nytt avsnitt', + 'view' => 'Visa podcast', + 'edit' => 'Redigera podcast', + 'publish' => 'Publicera podcasten', + 'publish_edit' => 'Redigera publikation', + 'delete' => 'Ta bort podcast', + 'see_episodes' => 'Se avsnitt', + 'see_contributors' => 'Se bidragsgivare', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Gå till sida', + 'latest_episodes' => 'Senaste avsnitt', + 'see_all_episodes' => 'Se alla avsnitt', + 'draft' => 'Utkast', + 'messages' => [ + 'createSuccess' => 'Podcast har skapats!', + 'editSuccess' => 'Podcasten har uppdaterats!', + 'importSuccess' => 'Podcasten har importerats!', + 'deleteSuccess' => 'Podcast @{podcast_handle} har raderats!', + 'deletePodcastMediaError' => 'Kunde inte ta bort podcast {type, select, + cover {omslag} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Misslyckades att ta bort avsnitt {episode_slug} {type, select, + transcript {transcript} + chapters {kapitel} + image {omslag} + audio {ljud} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Det gick inte att ta bort podcast-mediamappen {folder_path}. Du kan manuellt ta bort den från disken.', + 'podcastFeedUpdateSuccess' => 'Lyckad uppdatering: {number_of_new_episodes, plural, + one {# episoden var} + other {# episoder var} + } lades till i podcasten!', + 'podcastFeedUpToDate' => 'Podcasten är redan uppdaterad.', + 'publishError' => 'Denna podcast är antingen redan publicerad eller schemalagd för publicering.', + 'publishEditError' => 'Denna podcast är inte schemalagd för publicering.', + 'publishCancelSuccess' => 'Podcast publicering avbröts!', + 'scheduleDateError' => 'Schemaläggningsdatum måste anges!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identitet', + 'identity_section_subtitle' => 'Dessa fält gör att du kan bli uppmärksammad.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast omslag', + 'cover_size_hint' => 'Omslaget måste vara fyrkantigt och minst 1400px brett och högt.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner måste ha ett 3:1-förhållande och vara minst 1500px bred.', + 'banner_delete' => 'Ta bort podcast banner', + 'title' => 'Rubrik', + 'handle' => 'Hantera', + 'handle_hint' => + 'Används för att identifiera podcasten. Versaler, gemener, siffror och understrykningar accepteras.', + 'type' => [ + 'label' => 'Typ', + 'episodic' => 'Episodic', + 'episodic_hint' => 'Om avsnitt är avsedda att konsumeras utan någon specifik ordning. Nyaste avsnitt kommer att presenteras först.', + 'serial' => 'Serie', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Beskrivning', + 'classification_section_title' => 'Klassificering', + 'classification_section_subtitle' => + 'Dessa fält kommer att påverka din publik och konkurrens.', + 'language' => 'Språk', + 'category' => 'Kategori', + 'category_placeholder' => 'Välj en kategori…', + 'other_categories' => 'Andra kategorier', + 'parental_advisory' => [ + 'label' => 'Föräldrarådgivande', + 'hint' => 'Innehåller det olämpligt innehåll?', + 'undefined' => 'odefinierad', + 'clean' => 'Ren', + 'explicit' => 'Uteslutande', + ], + 'author_section_title' => 'Författare', + 'author_section_subtitle' => 'Vem hanterar podcasten?', + 'owner_name' => 'Ägarens namn', + 'owner_name_hint' => + 'Endast för administrativt bruk. Synlig i det offentliga RSS-flödet.', + 'owner_email' => 'Ägarens e-post', + 'owner_email_hint' => + 'Kommer att användas av de flesta plattformar för att verifiera podcast-ägandet. Synlig i det offentliga RSS-flödet.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Utgivare', + 'publisher_hint' => + 'Gruppen som ansvarar för att skapa showen. Ofta hänvisar man till moderbolaget eller nätverket av en podcast. Detta fält är ibland märkt som "Författare".', + 'copyright' => 'Copyright', + 'location_section_title' => 'Plats', + 'location_section_subtitle' => 'Vilken plats handlar denna podcast om?', + 'location_name' => 'Platsnamn eller adress', + 'location_name_hint' => 'Detta kan vara en riktig plats eller fiktiv', + 'monetization_section_title' => 'Inkomster', + 'monetization_section_subtitle' => + 'Tjäna pengar tack vare din publik.', + 'premium' => 'Premium', + 'premium_by_default' => 'Avsnitt måste anges som premium som standard', + 'premium_by_default_hint' => 'Podcast avsnitt kommer att markeras som premium som standard. Du kan fortfarande välja att ställa in några avsnitt, trailers eller bonusar som offentliga.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Betalning pekare för Web Monetization', + 'payment_pointer_hint' => + 'Detta är din där du kommer att få pengar tack vare Web Monetization', + 'advanced_section_title' => 'Avancerade parametrar', + 'advanced_section_subtitle' => + 'Om du behöver RSS-taggar som Castopod inte hanterar, ställ in dem här.', + 'custom_rss' => 'Anpassade RSS-taggar för podcasten', + 'custom_rss_hint' => 'Detta kommer att injiceras i kanal taggen.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'Ny flödes-URL', + 'new_feed_url_hint' => 'Använd detta fält när du flyttar till en annan domän eller podcast webbhotell. Som standard är värdet inställt på nuvarande RSS-URL om podcasten importeras.', + 'old_feed_url' => 'Gammal flödes-URL', + 'partnership' => 'Samarbete', + 'partner_id' => 'ID', + 'partner_link_url' => 'Länk url', + 'partner_image_url' => 'Bild-URL', + 'partner_id_hint' => 'Din egen partner ID', + 'partner_link_url_hint' => 'Den generiska partnerns länkadress', + 'partner_image_url_hint' => 'Den generiska partnerns bildadress', + 'block' => 'Podcast bör döljas från offentliga kataloger', + 'block_hint' => + 'Podcasten visar eller dölj status: att växla på detta hindrar hela podcasten från att visas i Apple Podcasts, Google Podcasts, och alla tredjepartsappar som drar program från dessa kataloger. (Inte garanterat)', + 'complete' => 'Podcast kommer inte att ha nya avsnitt', + 'lock' => 'Förhindra podcast från att kopieras', + 'lock_hint' => + 'Syftet är att berätta för andra podcast-plattformar om de får importera detta flöde. Ett värde av ja innebär att varje försök att importera detta flöde till en ny plattform bör avvisas.', + 'submit_create' => 'Skapa podcast', + 'submit_edit' => 'Spara podcast', + ], + 'category_options' => [ + 'uncategorized' => 'okategoriserad', + 'arts' => 'Konst', + 'business' => 'Företagande', + 'comedy' => 'Komedi', + 'education' => 'Utbildning', + 'fiction' => 'Fiktion', + 'government' => 'Myndighet', + 'health_and_fitness' => 'Hälsa & Träning', + 'history' => 'Historia', + 'kids_and_family' => 'Barn & Familj', + 'leisure' => 'Fritid', + 'music' => 'Musik', + 'news' => 'Nyheter', + 'religion_and_spirituality' => 'Religion & Andlighet', + 'science' => 'Vetenskap', + 'society_and_culture' => 'Samhälle & Kultur', + 'sports' => 'Sport', + 'technology' => 'Teknologi', + 'true_crime' => 'Sann brottslighet', + 'tv_and_film' => 'TV & Film', + 'books' => 'Böcker', + 'design' => 'Design', + 'fashion_and_beauty' => 'Mode & Skönhet', + 'food' => 'Mat', + 'performing_arts' => 'Scenkonst', + 'visual_arts' => 'Visuell konst', + 'careers' => 'Karriärer', + 'entrepreneurship' => 'Entreprenörskap', + 'investing' => 'Investering', + 'management' => 'Management', + 'marketing' => 'Marknadsföring', + 'non_profit' => 'Ideell organisation', + 'comedy_interviews' => 'Komedi Intervjuer', + 'improv' => 'Förbättra', + 'stand_up' => 'Stand-Up', + 'courses' => 'Kurser', + 'how_to' => 'Så funkar det', + 'language_learning' => 'Språkinlärning', + 'self_improvement' => 'Självförbättring', + 'comedy_fiction' => 'Komedi fiktion', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternativ Hälsa', + 'fitness' => 'Träning', + 'medicine' => 'Medicin', + 'mental_health' => 'Mental hälsa', + 'nutrition' => 'Näring', + 'sexuality' => 'Sexualitet', + 'education_for_kids' => 'Utbildning för barn', + 'parenting' => 'Föräldraskap', + 'pets_and_animals' => 'Husdjur & djur', + 'stories_for_kids' => 'Berättelser för barn', + 'animation_and_manga' => 'Animering & Manga', + 'automotive' => 'Fordon', + 'aviation' => 'Luftfart', + 'crafts' => 'Hantverk', + 'games' => 'Spel', + 'hobbies' => 'Fritidsintressen', + 'home_and_garden' => 'Hem och trädgård', + 'video_games' => 'Videospel', + 'music_commentary' => 'Kommentar från musik', + 'music_history' => 'Musikhistorik', + 'music_interviews' => 'Musikintervjuer', + 'business_news' => 'Företagsnyheter', + 'daily_news' => 'Dagliga nyheter', + 'entertainment_news' => 'Underhållningsnyheter', + 'news_commentary' => 'Nyheter Kommentar', + 'politics' => 'Politik', + 'sports_news' => 'Sportnyheter', + 'tech_news' => 'Tekniknyheter', + 'buddhism' => 'Budism', + 'christianity' => 'Kristendom', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judendom', + 'religion' => 'Religion', + 'spirituality' => 'Andlighet', + 'astronomy' => 'Astronomi', + 'chemistry' => 'Kemi', + 'earth_sciences' => 'Jordvetenskap', + 'life_sciences' => 'Livsvetenskaper', + 'mathematics' => 'Matematik', + 'natural_sciences' => 'Naturvetenskap', + 'nature' => 'Natur', + 'physics' => 'Fysik', + 'social_sciences' => 'Samhällsvetenskap', + 'documentary' => 'Dokumentär', + 'personal_journals' => 'Personliga tidsskrifter', + 'philosophy' => 'Filosofi', + 'places_and_travel' => 'Resor & Resmål', + 'relationships' => 'Relationer', + 'baseball' => 'Baseball', + 'basketball' => 'Basket', + 'cricket' => 'Kricket', + 'fantasy_sports' => 'Fantasy Sport', + 'football' => 'Fotboll', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Löpning', + 'soccer' => 'Fotboll', + 'swimming' => 'Simning', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyboll', + 'wilderness' => 'Vildmark', + 'wrestling' => 'Brottning', + 'after_shows' => 'Efter serier', + 'film_history' => 'Film Historik', + 'film_interviews' => 'Filmintervjuer', + 'film_reviews' => 'Filmrecensioner', + 'tv_reviews' => 'TV recensioner', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Tillbaka till podcast instrumentpanel', + 'post' => 'Ditt meddelande inlägg', + 'post_hint' => + "Skriv ett meddelande för att meddela publiceringen av din podcast. Meddelandet kommer att visas på din podcasts hemsida.", + 'message_placeholder' => 'Skriv ditt meddelande…', + 'submit' => 'Publicera', + 'publication_date' => 'Publiceringsdatum', + 'publication_method' => [ + 'now' => 'Nu', + 'schedule' => 'Schemalägg', + ], + 'scheduled_publication_date' => 'Planerat publiceringsdatum', + 'scheduled_publication_date_hint' => + 'Du kan schemalägga podcast-utgåvan genom att ställa in ett framtida publiceringsdatum. Detta fält måste formateras som YYYY-MM-DD HH:mm', + 'submit_edit' => 'Redigera publikation', + 'cancel_publication' => 'Avbryt publicering', + 'message_warning' => 'Du skrev inte ett meddelande för ditt tillkännagivande!', + 'message_warning_hint' => 'Att ha ett meddelande ökar socialt engagemang, vilket resulterar i en bättre synlighet för din podcast.', + 'message_warning_submit' => 'Publicera ändå', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'utkastläge', + 'not_published' => 'Denna podcast är ännu inte publicerad.', + 'scheduled' => 'Denna podcast är schemalagd för publicering på {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Ta bort podcasten kommer att ta bort alla avsnitt, mediefiler, inlägg och analytics i samband med det. Denna åtgärd är oåterkallelig, du kommer inte att kunna hämta dem efteråt.", + 'understand' => 'Jag förstår, jag vill att podcasten ska raderas permanent', + 'submit' => 'Radera', + ], + 'by' => 'Av {publisher}', + 'season' => 'Säsong {seasonNumber}', + 'list_of_episodes_year' => '{year} avsnitt ({episodeCount})', + 'list_of_episodes_season' => + 'Säsong {seasonNumber} avsnitt ({episodeCount})', + 'no_episode' => 'Inga avsnitt hittades!', + 'follow' => 'Följ', + 'followers' => '{numberOfFollowers, plural, + one {# följare} + other {# följare} + }', + 'posts' => '{numberOfPosts, plural, + one {# inlägg} + other {# inlägg} + }', + 'activity' => 'Aktivitet', + 'episodes' => 'Avsnitt', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Finansierar länkar för {podcastTitle}', + 'find_on' => 'Hitta {podcastTitle} på', + 'listen_on' => 'Lyssna på', +]; diff --git a/modules/Admin/Language/sv/PodcastNavigation.php b/modules/Admin/Language/sv/PodcastNavigation.php new file mode 100644 index 00000000..383f8817 --- /dev/null +++ b/modules/Admin/Language/sv/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Gå till podcast sida', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast instrumentpanel', + 'podcast-view' => 'Hem', + 'podcast-edit' => 'Redigera podcast', + 'podcast-persons-manage' => 'Hantera personer', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Avsnitt', + 'episode-list' => 'Alla avsnitt', + 'episode-create' => 'Nytt avsnitt', + 'analytics' => 'Statistik', + 'podcast-analytics' => 'Lyssnar översikt', + 'podcast-analytics-webpages' => 'Besök på webbsidor', + 'podcast-analytics-locations' => 'Platser', + 'podcast-analytics-unique-listeners' => 'Unika lyssnare', + 'podcast-analytics-players' => 'Spelare', + 'podcast-analytics-listening-time' => 'Lyssningstid', + 'podcast-analytics-time-periods' => 'Tidsperioder', + 'monetization' => 'Monetization', + 'subscription-list' => 'Alla prenumerationer', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Bidragsgivare', + 'contributor-list' => 'Alla bidragsgivare', + 'contributor-add' => 'Lägg till bidragsgivare', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Sociala nätverk', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/sv/Settings.php b/modules/Admin/Language/sv/Settings.php new file mode 100644 index 00000000..6a595e0a --- /dev/null +++ b/modules/Admin/Language/sv/Settings.php @@ -0,0 +1,58 @@ + 'Allmänna inställningar', + 'instance' => [ + 'title' => 'Instans', + 'site_icon' => 'Ikon för webbplats', + 'site_icon_delete' => 'Ta bort webbplatsikonen', + 'site_icon_hint' => 'Webbplatsikoner är vad du ser på dina webbläsarflikar, bokmärkesfältet och när du lägger till en webbplats som en genväg på mobila enheter.', + 'site_icon_helper' => 'Ikonen måste vara kvadratisk och minst 512px bred och hög.', + 'site_name' => 'Webbplatsens namn', + 'site_description' => 'Webbplatsbeskrivning', + 'submit' => 'Spara', + 'editSuccess' => 'Instansen har uppdaterats!', + 'deleteIconSuccess' => 'Webbplatsikonen har tagits bort!', + ], + 'images' => [ + 'title' => 'Bilder', + 'subtitle' => 'Här kan du regenerera alla bilder baserat på originalen som laddats upp. Att användas om du upptäcker att vissa bilder saknas. Denna uppgift kan ta ett tag.', + 'regenerate' => 'Regenerera bilder', + 'regenerationSuccess' => 'Alla bilder har återskapats framgångsrikt!', + ], + 'housekeeping' => [ + 'title' => 'Städning', + 'subtitle' => 'Kör olika städuppgifter. Använd denna funktion om du någonsin stöter på problem med mediefiler eller dataintegritet. Dessa uppgifter kan ta ett tag.', + 'reset_counts' => 'Återställ räknare', + 'reset_counts_helper' => 'Detta alternativ kommer att räkna om och återställa alla data räknas (antal följare, inlägg, kommentarer, …).', + 'rewrite_media' => 'Skriv om media metadata', + 'rewrite_media_helper' => 'Detta alternativ kommer att ta bort alla överflödiga mediefiler och återskapa dem (bilder, ljudfiler, avskrifter, kapitel, …)', + 'rename_episodes_files' => 'Döp om avsnittets ljudfiler', + 'rename_episodes_files_hint' => 'Detta alternativ kommer att byta namn på alla avsnitt ljudfiler till en slumpmässig sträng av tecken. Använd detta om en av dina privata episoder länk läckte eftersom detta effektivt kommer att dölja det.', + 'clear_cache' => 'Rensa all cache', + 'clear_cache_helper' => 'Det här alternativet kommer att radera redis cache eller skrivbara/cache-filer.', + 'run' => 'Kör städning', + 'runSuccess' => 'Städning har körts framgångsrikt!', + ], + 'theme' => [ + 'title' => 'Tema', + 'accent_section_title' => 'Accentfärg', + 'accent_section_subtitle' => 'Välj färg för att bestämma utseendet och känslan på alla offentliga sidor.', + 'pine' => 'Tall', + 'crimson' => 'Karmosinröd', + 'amber' => 'Bärnsten', + 'lake' => 'Sjö', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Spara', + 'setInstanceThemeSuccess' => 'Temat har uppdaterats!', + ], +]; diff --git a/modules/Admin/Language/sv/Soundbite.php b/modules/Admin/Language/sv/Soundbite.php new file mode 100644 index 00000000..fd80f828 --- /dev/null +++ b/modules/Admin/Language/sv/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Ljudklipp', + 'soundbite' => 'Ljudklipp', + ], + 'messages' => [ + 'createSuccess' => 'Ljudklipp har skapats!', + 'deleteSuccess' => 'Ljudklipp har tagits bort!', + ], + 'form' => [ + 'title' => 'Nytt ljudklipp', + 'soundbite_title' => 'Ljudklipp titel', + 'start_time' => 'Starta vid', + 'duration' => 'Längd', + 'submit' => 'Skapa ljudklipp', + ], + 'play' => 'Spela ljudklipp', + 'stop' => 'Stoppa ljudklipp', + 'create' => 'Nytt ljudklipp', + 'delete' => 'Ta bort ljudklipp', +]; diff --git a/modules/Admin/Language/sv/Validation.php b/modules/Admin/Language/sv/Validation.php new file mode 100644 index 00000000..8dc9341e --- /dev/null +++ b/modules/Admin/Language/sv/Validation.php @@ -0,0 +1,17 @@ + + '{field} är antingen inte en bild, eller så är den inte bred eller tillräckligt hög.', + 'is_image_ratio' => + '{field} är antingen inte en bild eller inte av rätt förhållande.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/sv/VideoClip.php b/modules/Admin/Language/sv/VideoClip.php new file mode 100644 index 00000000..a94406b9 --- /dev/null +++ b/modules/Admin/Language/sv/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Videoklipp', + 'status' => [ + 'label' => 'Status', + 'queued' => 'köad', + 'queued_hint' => 'Klipp väntar på att bearbetas.', + 'pending' => 'väntande', + 'pending_hint' => 'Klipp kommer att genereras inom kort.', + 'running' => 'körs', + 'running_hint' => 'Klipp genereras.', + 'failed' => 'misslyckades', + 'failed_hint' => 'Klipp kunde inte genereras: skript misslyckades.', + 'passed' => 'godkänd', + 'passed_hint' => 'Klipp har skapats framgångsrikt!', + ], + 'clip' => 'Klipp', + 'duration' => 'Varaktighet för jobb', + ], + 'title' => 'Videoklipp: {videoClipLabel}', + 'download_clip' => 'Ladda ner klipp', + 'create' => 'Nytt videoklipp', + 'go_to_page' => 'Gå till klippsida', + 'retry' => 'Generering av nytt klipp', + 'delete' => 'Ta bort klipp', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'Det videoklipp du försöker skapa finns redan!', + 'addToQueueSuccess' => 'Videoklipp har lagts till i kön, väntar på att skapas!', + 'deleteSuccess' => 'Videoklipp har tagits bort!', + ], + 'format' => [ + 'landscape' => 'Liggande', + 'portrait' => 'Stående', + 'squared' => 'Kvadrat', + ], + 'form' => [ + 'title' => 'Nytt videoklipp', + 'params_section_title' => 'Parametrar för videoklipp', + 'clip_title' => 'Klipp titel', + 'format' => [ + 'label' => 'Välj ett format', + 'landscape_hint' => 'Med ett 16:9 förhållande, landskapsvideor är bra för PeerTube, Youtube och Vimeo.', + 'portrait_hint' => 'Med 9:16 förhållande, porträttfilmer är bra för TikTok, Youtube shorts och Instagram berättelser.', + 'squared_hint' => 'Med en 1:1 förhållande, fyrkantiga videor är bra för Mastodon, Facebook, Twitter och LinkedIn.', + ], + 'theme' => 'Välj ett tema', + 'start_time' => 'Starta vid', + 'duration' => 'Längd', + 'trim_start' => 'Trimma start', + 'trim_end' => 'Trimma slut', + 'submit' => 'Skapa videoklipp', + ], + 'requirements' => [ + 'title' => 'Krav ej uppfyllda', + 'missing' => 'Du har saknade krav. Se till att lägga till alla nödvändiga objekt som tillåts att skapa en video för detta avsnitt!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Grafik Rita (GD)', + 'freetype' => 'Freetyp bibliotek för GD', + 'transcript' => 'Avskrift fil (.srt)', + ], +]; diff --git a/modules/Admin/Language/uk/AboutCastopod.php b/modules/Admin/Language/uk/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/uk/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/uk/Breadcrumb.php b/modules/Admin/Language/uk/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/uk/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/uk/Charts.php b/modules/Admin/Language/uk/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/uk/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/uk/Common.php b/modules/Admin/Language/uk/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/uk/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/uk/Countries.php b/modules/Admin/Language/uk/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/uk/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/uk/Dashboard.php b/modules/Admin/Language/uk/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/uk/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/uk/Episode.php b/modules/Admin/Language/uk/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/uk/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/uk/EpisodeNavigation.php b/modules/Admin/Language/uk/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/uk/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/uk/Fediverse.php b/modules/Admin/Language/uk/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/uk/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/uk/Home.php b/modules/Admin/Language/uk/Home.php new file mode 100644 index 00000000..6249bab1 --- /dev/null +++ b/modules/Admin/Language/uk/Home.php @@ -0,0 +1,14 @@ + 'Усі подкасти', + 'no_podcast' => 'Подкастів не знайдено', +]; diff --git a/modules/Admin/Language/uk/Install.php b/modules/Admin/Language/uk/Install.php new file mode 100644 index 00000000..814cd8c2 --- /dev/null +++ b/modules/Admin/Language/uk/Install.php @@ -0,0 +1,61 @@ + 'Ручне налаштування', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Ім\'я хоста бази даних', + 'db_name' => 'Назва бази даних', + 'db_username' => 'Ім\'я користувача бази даних', + 'db_password' => 'Пароль бази даних', + 'db_prefix' => 'Префікс бази даних', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Обробник кешу', + 'cacheHandlerOptions' => [ + 'file' => 'Файл', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Далі', + 'submit' => 'Завершити установку', + 'create_superadmin' => 'Створіть свій обліковий запис головного адміністратора', + 'email' => 'Пошта', + 'username' => 'Ім\'я користувача', + 'password' => 'Пароль', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ваш обліковий запис суперадміністратора було успішно створено. Увійдіть, щоб почати подкасти!', + 'databaseConnectError' => + 'Кастопод не зміг підключитись до бази даних. Змініть конфігурацію бази даних і повторіть спробу.', + 'writeError' => + "Не вдалося створити/записати файл `.env`. Ви повинні створити його вручну, перейшовши шаблон файлу `.env.example` в пакеті Castopode.", + ], +]; diff --git a/modules/Admin/Language/uk/Navigation.php b/modules/Admin/Language/uk/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/uk/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/uk/Notifications.php b/modules/Admin/Language/uk/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/uk/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/uk/Page.php b/modules/Admin/Language/uk/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/uk/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/uk/Pager.php b/modules/Admin/Language/uk/Pager.php new file mode 100644 index 00000000..c940f604 --- /dev/null +++ b/modules/Admin/Language/uk/Pager.php @@ -0,0 +1,21 @@ + 'Навігація між сторінками', + 'first' => 'Перший', + 'previous' => 'Попередній', + 'next' => 'Наступний', + 'last' => 'Останній', + 'older' => 'Старші', + 'newer' => 'Новіші', + 'invalidTemplate' => '{0} не є правильним шаблоном Пейджера.', + 'invalidPaginationGroup' => '{0} - некоректна група нумерацій.', +]; diff --git a/modules/Admin/Language/uk/Person.php b/modules/Admin/Language/uk/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/uk/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/uk/Platforms.php b/modules/Admin/Language/uk/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/uk/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/uk/Podcast.php b/modules/Admin/Language/uk/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/uk/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/uk/PodcastNavigation.php b/modules/Admin/Language/uk/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/uk/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/uk/Settings.php b/modules/Admin/Language/uk/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/uk/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/uk/Soundbite.php b/modules/Admin/Language/uk/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/uk/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/uk/Validation.php b/modules/Admin/Language/uk/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/uk/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/uk/VideoClip.php b/modules/Admin/Language/uk/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/uk/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Admin/Language/zh-hans/AboutCastopod.php b/modules/Admin/Language/zh-hans/AboutCastopod.php new file mode 100644 index 00000000..9817b219 --- /dev/null +++ b/modules/Admin/Language/zh-hans/AboutCastopod.php @@ -0,0 +1,22 @@ + '关于 Castopod', + 'host_name' => '主机名', + 'version' => 'Castopod 版本', + 'php_version' => 'PHP 版本', + 'os' => '操作系统', + 'languages' => '语言', + 'update_database' => '更新数据库', + 'messages' => [ + 'databaseUpdateSuccess' => '数据库是最新的!', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Breadcrumb.php b/modules/Admin/Language/zh-hans/Breadcrumb.php new file mode 100644 index 00000000..db129570 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Breadcrumb.php @@ -0,0 +1,57 @@ + '面包屑导航', + config('Admin') + ->gateway => '主页', + 'podcasts' => '播客', + 'episodes' => '剧集', + 'subscriptions' => '订阅', + 'contributors' => '贡献者', + 'pages' => '页', + 'settings' => '设置', + 'theme' => '主题', + 'about' => '关于', + 'add' => '添加', + 'new' => '新建', + 'edit' => '编辑', + 'persons' => '人', + 'publish' => '发布', + 'publish-edit' => '编辑发布', + 'publish-date-edit' => '编辑发布日期', + 'unpublish' => '取消发布', + 'delete' => '删除', + 'remove' => '移除', + 'fediverse' => '联邦宇宙', + 'blocked-actors' => '已屏蔽演员', + 'blocked-domains' => '已屏蔽域名', + 'users' => '用户', + 'my-account' => '我的帐户', + 'change-password' => '修改密码', + 'imports' => '导入', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => '平台', + 'social' => '社交网络', + 'funding' => '资金支持', + 'monetization-other' => 'other monetization', + 'analytics' => '统计数据', + 'locations' => '位置', + 'webpages' => '网页', + 'unique-listeners' => '独特的听众', + 'players' => '播放', + 'listening-time' => '收听时间', + 'time-periods' => '时间段', + 'soundbites' => '原声摘要', + 'video-clips' => '视频素材', + 'embed' => '嵌入式播放器', + 'notifications' => '通知', + 'suspend' => '暂停', +]; diff --git a/modules/Admin/Language/zh-hans/Charts.php b/modules/Admin/Language/zh-hans/Charts.php new file mode 100644 index 00000000..e1da7b26 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Charts.php @@ -0,0 +1,41 @@ + '按服务分类的剧集下载量(过去一周)', + 'by_player_weekly' => '按播放量的剧集下载量(过去一周)', + 'by_player_yearly' => '按播放量的剧集下载量(过去一年)', + 'by_device_weekly' => '按设备分类的剧集下载量(过去一周)', + 'by_os_weekly' => '按操作系统分类的剧集下载量(过去一周)', + 'podcast_by_region' => '按地区的剧集下载量(过去一周)', + 'unique_daily_listeners' => '每日独立听众', + 'unique_monthly_listeners' => '每月独立听众', + 'by_browser' => '网页端使用情况(过去一周)', + 'podcast_by_day' => '剧集每日下载量', + 'podcast_by_month' => '剧集每月下载量', + 'episode_by_day' => '剧集每日下载(前60天)', + 'episode_by_month' => '剧集每月下载', + 'episodes_by_day' => + '5 个最新剧集下载(前60天)', + 'by_country_weekly' => '按国家/地区的剧集下载量(过去一周)', + 'by_country_yearly' => '按国家/地区的剧集下载量(过去一年)', + 'by_domain_weekly' => '网页端访问情况(过去一周)', + 'by_domain_yearly' => '网页端访问情况(过去一年)', + 'by_entry_page' => '登录页面的访问情况(过去一周)', + 'podcast_bots' => '机器人(爬虫)', + 'daily_listening_time' => '每日累计收听时间', + 'monthly_listening_time' => '每月累计收听时间', + 'by_weekday' => '按工作日(过去60天)', + 'by_hour' => '按一天中的时间(过去60天)', + 'podcast_by_bandwidth' => '每日使用带宽(MB)', + 'total_storage_by_month' => '每月存储量 (MB)', + 'total_bandwidth_by_month' => '每月使用带宽(MB)', + 'total_bandwidth_by_month_limit' => '每月限制为 {totalBandwidth}', +]; diff --git a/modules/Admin/Language/zh-hans/Common.php b/modules/Admin/Language/zh-hans/Common.php new file mode 100644 index 00000000..5909a764 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Common.php @@ -0,0 +1,52 @@ + '是', + 'no' => '否', + 'cancel' => '取消', + 'optional' => '可选', + 'more' => '更多', + 'no_data' => '找不到数据!', + 'close' => '关闭', + 'edit' => '编辑', + 'copy' => '复制', + 'copied' => '复制成功!', + 'home' => '主页', + 'explicit' => '限制级', + 'powered_by' => '由 {castopod} 提供支持', + 'actions' => '操作', + 'pageInfo' => '第 {currentPage} 页,共 {pageCount} 页', + 'go_back' => '返回', + 'forms' => [ + 'editor' => [ + 'write' => '内容编辑', + 'preview' => '预览', + 'help' => '由 Markdown 驱动', + ], + 'multiSelect' => [ + 'selectText' => '点击选择', + 'loadingText' => '载入中...', + 'noResultsText' => '没有找到结果', + 'noChoicesText' => '没有可供选择的选项', + 'maxItemText' => '无法添加更多项目', + ], + 'upload_file' => '上传文件', + 'remote_url' => '远程网址', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => '播放', + 'playing' => '正在播放', + ], + 'size_limit' => '大小限制:{0}。', + 'choose_interact' => '选择互动方式', + 'view' => '查看', +]; diff --git a/modules/Admin/Language/zh-hans/Countries.php b/modules/Admin/Language/zh-hans/Countries.php new file mode 100644 index 00000000..5c66deed --- /dev/null +++ b/modules/Admin/Language/zh-hans/Countries.php @@ -0,0 +1,264 @@ + '安道尔', + 'AE' => '阿拉伯联合酋长国', + 'AF' => '阿富汗', + 'AG' => '安提瓜和巴布达', + 'AI' => '安圭拉', + 'AL' => '阿尔巴尼亚', + 'AM' => '亚美尼亚', + 'AO' => '安哥拉', + 'AQ' => '南极洲', + 'AR' => '阿根廷', + 'AS' => '美属萨摩亚', + 'AT' => '奥地利', + 'AU' => '澳大利亚', + 'AW' => '阿鲁巴', + 'AX' => '奥兰群岛', + 'AZ' => '阿塞拜疆', + 'BA' => '波黑', + 'BB' => '巴巴多斯', + 'BD' => '孟加拉国', + 'BE' => '比利时', + 'BF' => '布基纳法索', + 'BG' => '保加利亚', + 'BH' => '巴林', + 'BI' => '布隆迪', + 'BJ' => '贝宁', + 'BL' => '圣巴泰勒米', + 'BM' => '百慕大', + 'BN' => '文莱达鲁萨兰国', + 'BO' => '玻利维亚', + 'BQ' => '荷兰加勒比区', + 'BR' => '巴西', + 'BS' => '巴哈马', + 'BT' => '不丹', + 'BV' => '布韦岛', + 'BW' => '博茨瓦纳', + 'BY' => '白俄罗斯', + 'BZ' => '伯利兹', + 'CA' => '加拿大', + 'CC' => '科科斯(基林) 群岛', + 'CD' => '刚果(金)', + 'CF' => '中非共和国', + 'CG' => '刚果', + 'CH' => '瑞士', + 'CI' => "科特迪瓦", + 'CK' => '库克群岛', + 'CL' => '智利', + 'CM' => '喀麦隆', + 'CN' => '中国', + 'CO' => '哥伦比亚', + 'CR' => '哥斯达黎加', + 'CU' => '古巴', + 'CV' => '佛得角', + 'CW' => '库拉索', + 'CX' => '圣诞岛', + 'CY' => '塞浦路斯', + 'CZ' => '捷克', + 'DE' => '德国', + 'DJ' => '吉布提', + 'DK' => '丹麦', + 'DM' => '多米尼克', + 'DO' => '多米尼加', + 'DZ' => '阿尔及利亚', + 'EC' => '厄瓜多尔', + 'EE' => '爱沙尼亚', + 'EG' => '埃及', + 'EH' => '西撒哈拉', + 'ER' => '厄立特里亚', + 'ES' => '西班牙', + 'ET' => '埃塞俄比亚', + 'FI' => '芬兰', + 'FJ' => '斐济', + 'FK' => '福克兰群岛(马尔维纳斯)', + 'FM' => '密克罗尼西亚联邦', + 'FO' => '法罗群岛', + 'FR' => '法国', + 'GA' => '加蓬', + 'GB' => '英国', + 'GD' => '格林纳达', + 'GE' => '格鲁吉亚', + 'GF' => '法属圭亚那', + 'GG' => '根西岛', + 'GH' => '加纳', + 'GI' => '直布罗陀', + 'GL' => '格陵兰', + 'GM' => '冈比亚', + 'GN' => '几内亚', + 'GP' => '法属瓜德罗普岛', + 'GQ' => '赤道几内亚', + 'GR' => '希腊', + 'GS' => '南乔治亚和南桑威奇群岛', + 'GT' => '危地马拉', + 'GU' => '关岛', + 'GW' => '几内亚比绍', + 'GY' => '圭亚那', + 'HK' => '中国香港', + 'HM' => '赫德岛和麦克唐纳群岛', + 'HN' => '洪都拉斯', + 'HR' => '克罗地亚', + 'HT' => '海地', + 'HU' => '匈牙利', + 'ID' => '印度尼西亚', + 'IE' => '爱尔兰', + 'IL' => '以色列', + 'IM' => '马恩岛', + 'IN' => '印度', + 'IO' => '英属印度洋领地', + 'IQ' => '伊拉克', + 'IR' => '伊朗', + 'IS' => '冰岛', + 'IT' => '意大利', + 'JE' => '泽西', + 'JM' => '牙买加', + 'JO' => '约旦', + 'JP' => '日本', + 'KE' => '肯尼亚', + 'KG' => '吉尔吉斯斯坦', + 'KH' => '柬埔寨', + 'KI' => '基里巴斯', + 'KM' => '科摩罗', + 'KN' => '圣基茨和尼维斯', + 'KP' => "朝鲜", + 'KR' => '韩国', + 'KW' => '科威特', + 'KY' => '开曼群岛', + 'KZ' => '哈萨克斯坦', + 'LA' => "老挝", + 'LB' => '黎巴嫩', + 'LC' => '圣卢西亚', + 'LI' => '列支敦士登', + 'LK' => '斯里兰卡', + 'LR' => '利比里亚', + 'LS' => '莱索托', + 'LT' => '立陶宛', + 'LU' => '卢森堡', + 'LV' => '拉脱维亚', + 'LY' => '利比亚', + 'MA' => '摩洛哥', + 'MC' => '摩纳哥', + 'MD' => '摩尔多瓦', + 'ME' => '黑山', + 'MF' => '法属圣马丁', + 'MG' => '马达加斯加', + 'MH' => '马绍尔群岛', + 'MK' => '马其顿、前南斯拉夫共和国', + 'ML' => '马里', + 'MM' => '缅甸', + 'MN' => '蒙古', + 'MO' => '中国澳门', + 'MP' => '北马里亚纳群岛', + 'MQ' => '马提尼克岛', + 'MR' => '毛里塔尼亚', + 'MS' => '蒙特塞拉特', + 'MT' => '马耳他', + 'MU' => '毛里求斯', + 'MV' => '马尔代夫', + 'MW' => '马拉维', + 'MX' => '墨西哥', + 'MY' => '马来西亚', + 'MZ' => '莫桑比克', + 'N/A' => '不适用(本地IP…)', + 'NA' => '纳米比亚', + 'NC' => '新喀里多尼亚', + 'NE' => '尼日尔', + 'NF' => '诺福尔克岛', + 'NG' => '尼日利亚', + 'NI' => '尼加拉瓜', + 'NL' => '荷兰', + 'NO' => '挪威', + 'NP' => '尼泊尔', + 'NR' => '瑙鲁', + 'NU' => '纽埃', + 'NZ' => '新西兰', + 'OM' => '阿曼', + 'PA' => '巴拿马', + 'PE' => '秘鲁', + 'PF' => '法属波利尼西亚', + 'PG' => '巴布亚新几内亚', + 'PH' => '菲律宾', + 'PK' => '巴基斯坦', + 'PL' => '波兰', + 'PM' => '圣皮埃尔和密克隆', + 'PN' => '皮特凯恩群岛', + 'PR' => '波多黎各', + 'PS' => '巴勒斯坦', + 'PT' => '葡萄牙', + 'PW' => '帕劳', + 'PY' => '巴拉圭', + 'QA' => '卡塔尔', + 'RE' => '留尼旺', + 'RO' => '罗马尼亚', + 'RS' => '塞尔维亚', + 'RU' => '俄罗斯', + 'RW' => '卢旺达', + 'SA' => '沙特阿拉伯', + 'SB' => '所罗门群岛', + 'SC' => '塞舌尔', + 'SD' => '苏丹', + 'SE' => '瑞典', + 'SG' => '新加坡', + 'SH' => '圣赫勒拿、阿森松与特里斯坦达库尼亚', + 'SI' => '斯洛文尼亚', + 'SJ' => '斯瓦尔巴和扬马延岛', + 'SK' => '斯洛伐克', + 'SL' => '塞拉利昂', + 'SM' => '圣马力诺', + 'SN' => '塞内加尔', + 'SO' => '索马里', + 'SR' => '苏里南', + 'SS' => '南苏丹', + 'ST' => '圣多美和普林西比', + 'SV' => '萨尔瓦多', + 'SX' => '荷属圣马丁', + 'SY' => '叙利亚', + 'SZ' => '斯威士兰', + 'TC' => '特克斯和凯科斯群岛', + 'TD' => '乍得', + 'TF' => '法属南半球领地', + 'TG' => '多哥', + 'TH' => '泰国', + 'TJ' => '塔吉克斯坦', + 'TK' => '托克劳', + 'TL' => '东帝汶', + 'TM' => '土库曼斯坦', + 'TN' => '突尼斯', + 'TO' => '汤加', + 'TR' => '土耳其', + 'TT' => '特立尼达和多巴哥', + 'TV' => '图瓦卢', + 'TW' => '中国台湾', + 'TZ' => '坦桑尼亚', + 'UA' => '乌克兰', + 'UG' => '乌干达', + 'UM' => '美国本土外小岛屿', + 'US' => '美国', + 'UY' => '乌拉圭', + 'UZ' => '乌兹别克斯坦', + 'VA' => '梵蒂冈', + 'VC' => '圣文森特和格林纳丁斯', + 'VE' => '委内瑞拉', + 'VG' => '英属维京群岛', + 'VI' => '美属维京群岛', + 'VN' => '越南', + 'VU' => '瓦努阿图', + 'WF' => '瓦利斯和富图纳', + 'WS' => '萨摩亚', + 'YE' => '也门', + 'YT' => '马约特', + 'ZA' => '南非', + 'ZM' => '赞比亚', + 'ZW' => '津巴布韦', +]; diff --git a/modules/Admin/Language/zh-hans/Dashboard.php b/modules/Admin/Language/zh-hans/Dashboard.php new file mode 100644 index 00000000..2dd43f9f --- /dev/null +++ b/modules/Admin/Language/zh-hans/Dashboard.php @@ -0,0 +1,28 @@ + '管理面板', + 'welcome_message' => '欢迎来到管理区域!', + 'podcasts' => [ + 'title' => '播客', + 'not_found' => '没有已发布的播客', + 'last_published' => '最后发布于 {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => '剧集', + 'not_found' => '没有已发布的剧集', + 'last_published' => '最后发布于 {lastPublicationDate}', + ], + 'storage' => [ + 'title' => '存储', + 'subtitle' => '{totalUploaded} 共 {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Episode.php b/modules/Admin/Language/zh-hans/Episode.php new file mode 100644 index 00000000..49061df4 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Episode.php @@ -0,0 +1,225 @@ + '第 {seasonNumber} 节', + 'season_abbr' => '第 {seasonNumber} 节', + 'number' => '第 {episodeNumber} 集', + 'number_abbr' => '第 {episodeNumber} 集', + 'season_episode' => '第 {seasonNumber} 季第 {episodeNumber} 集', + 'season_episode_abbr' => '第 {seasonNumber} 季第 {episodeNumber} 集', + 'number_of_comments' => '{numberOfComments, plural, + other {# 评论} + other {# 评论} + }', + 'all_podcast_episodes' => '所有播客剧集', + 'back_to_podcast' => '返回播客', + 'edit' => '编辑', + 'preview' => 'Preview', + 'publish' => '发布', + 'publish_edit' => '编辑发布', + 'publish_date_edit' => '编辑发布日期', + 'unpublish' => '取消发布', + 'publish_error' => '剧集已被发布。', + 'publish_edit_error' => '剧集已被发布。', + 'publish_cancel_error' => '剧集已被发布。', + 'publish_date_edit_error' => '剧集尚未发布,你不能编辑其发布日期。', + 'publish_date_edit_future_error' => '剧集的发布日期只能设置为过去的日期! 如果你想重新安排日期,请先取消发布。', + 'publish_date_edit_success' => '剧集的发布日期已成功更新!', + 'unpublish_error' => '剧集尚未发布。', + 'delete' => '删除', + 'go_to_page' => '转到页面', + 'create' => '添加剧集', + 'publication_status' => [ + 'published' => '已发布', + 'with_podcast' => '已发布', + 'scheduled' => '已预约', + 'not_published' => '未发布', + ], + 'with_podcast_hint' => '与播客同时发布', + 'list' => [ + 'search' => [ + 'placeholder' => '搜索剧集', + 'clear' => '清除搜索内容', + 'submit' => '搜索', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + other {# 剧集} + other {# 剧集} + }', + 'episode' => '剧集', + 'visibility' => '可见性', + 'downloads' => '下载', + 'comments' => '评论', + 'actions' => '操作', + ], + 'messages' => [ + 'createSuccess' => '剧集已创建!', + 'editSuccess' => '剧集已更新!', + 'publishSuccess' => '{publication_status, select, + published {剧集已成功发布!} + scheduled {剧集已成功预约!} + with_podcast {剧集将与播客同时发布。} + other {此剧集未发布。} + }', + 'publishCancelSuccess' => '成功取消剧集发布!', + 'unpublishBeforeDeleteTip' => '你必须在删除之前取消发布剧集。', + 'scheduleDateError' => '计划日期必须设置!', + 'deletePublishedEpisodeError' => '请在删除之前取消发布该剧集。', + 'deleteSuccess' => '已删除剧集!', + 'deleteError' => '未能删除剧集 {type, select, + transcript {字幕} + chapters {章节} + image {封面} + audio {音频} + other {媒体} + }', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => '选中的剧集已存在。', + ], + 'form' => [ + 'file_size_error' => + '你的文件太大了!最大尺寸是 {0}。 在你的 php 配置文件中增加`memory_limit`, `upload_max_filesize` 和 `post_max_size` 值,然后重启你的 web 服务器上传文件。', + 'audio_file' => '音频文件', + 'audio_file_hint' => '选择一个 .mp3 或 .m4a 音频文件。', + 'info_section_title' => '剧集信息', + 'cover' => '剧集封面', + 'cover_hint' => + '如果你没有设置封面,将使用播客封面。', + 'cover_size_hint' => '封面必须是方形,而且至少 1400 px 宽度和高度。', + 'title' => '标题', + 'title_hint' => + '应包含清晰简洁的剧集名称。 不要在此处指定剧集或季编号。', + 'permalink' => '永久链接', + 'season_number' => '季', + 'episode_number' => '剧集', + 'type' => [ + 'label' => '类型', + 'full' => '全屏', + 'full_hint' => '完整内容 (剧集)', + 'trailer' => '预告片', + 'trailer_hint' => '代表当前剧集的的摘要', + 'bonus' => '奖金', + 'bonus_hint' => '剧集趣闻(例如,幕后信息与对演员的采访)或另一个剧集的推荐', + ], + 'premium_title' => '高级版', + 'premium' => '剧集仅允许高级订阅者访问', + 'parental_advisory' => [ + 'label' => '警告标记', + 'hint' => '剧集是否包含限制级内容?', + 'undefined' => '未定义', + 'clean' => '重置为默认', + 'explicit' => '限制级', + ], + 'show_notes_section_title' => '显示备注', + 'show_notes_section_subtitle' => + '清晰简洁,最多 4000 个字。显示笔记能帮助潜在的听众找到剧集。', + 'description' => '描述', + 'description_footer' => '说明页脚', + 'description_footer_hint' => + '此文本添加在每集描述的末尾,例如,是输入你链接的好位置。', + 'additional_files_section_title' => '附件', + 'additional_files_section_subtitle' => + '这些文件可能被其他播客平台用来生成提供更好的体验。 想要了解,请参阅 {podcastNamespaceLink}。', + 'location_section_title' => '位置', + 'location_section_subtitle' => '这个剧集在哪里?', + 'location_name' => '位置名称或地址', + 'location_name_hint' => '真或假位置都可以', + 'transcript' => '字幕(字幕/隐藏字幕)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => '下载字幕', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => '用于字幕的网址', + 'transcript_file_delete' => '删除字幕文件', + 'chapters' => '章节', + 'chapters_hint' => '文件必须为 JSON 格式。', + 'chapters_download' => '下载章节', + 'chapters_file' => '章节文件', + 'chapters_remote_url' => '章节文件网址', + 'chapters_file_delete' => '删除章节文件', + 'advanced_section_title' => '高级参数', + 'advanced_section_subtitle' => + '如果您需要 Castopod 无法处理的 RSS 标签,请在此处设置它们。', + 'custom_rss' => '剧集的自定义 RSS 标签', + 'custom_rss_hint' => '这将被注入到 ❬item❭ 标签中。', + 'block' => '剧集应该在公共目录中隐藏', + 'block_hint' => + '剧集显示或隐藏状态:打开此选项可防止整个剧集出现在 Apple 播客、Google 播客以及从此目录中提取剧集的任何第三方应用程序中。(不保证)', + 'submit_create' => '创建剧集', + 'submit_edit' => '保存剧集', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => '返回剧集控制面板', + 'post' => '你的公告播文', + 'post_hint' => + "写一条消息来宣布你有剧集发布。 此消息将向联邦宇宙中所有你的关注者推送,并在你的播客主页中出现。", + 'message_placeholder' => '写下你的消息…', + 'publication_date' => '发布日期', + 'publication_method' => [ + 'now' => '现在', + 'schedule' => '计划', + 'with_podcast' => '与播客一起发布', + ], + 'scheduled_publication_date' => '计划发布日期', + 'scheduled_publication_date_clear' => '清除发布日期', + 'scheduled_publication_date_hint' => + '你可以通过设置未来发布日期来安排剧集发布。此字段必须格式为 YYYY-MM-DD HH:mm', + 'submit' => '发布', + 'submit_edit' => '编辑发布', + 'cancel_publication' => '取消发布', + 'message_warning' => '你没有为你的公告播文写一条消息!', + 'message_warning_hint' => '有消息发送可以增加社交参与度,从而提高你的剧集曝光度。', + 'message_warning_submit' => '仍然发布', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => '新发布日期', + 'new_publication_date_hint' => '必须设置为过去的日期。', + 'submit' => '编辑发布日期', + ], + 'unpublish_form' => [ + 'disclaimer' => + "取消发布该剧集将删除相关的所有评论和播文,并将其从播客的 RSS 摘要中删除。", + 'understand' => '我明白,我想取消发布此剧集', + 'submit' => '取消发布', + ], + 'delete_form' => [ + 'disclaimer' => + "删除剧集将删除相关的所有媒体文件、评论、视频素材和原声摘要。", + 'understand' => '我明白,我想删除剧集', + 'submit' => '删除', + ], + 'embed' => [ + 'title' => '嵌入式播放器', + 'label' => + '选择主题色,将嵌入式播放器复制到剪贴板,然后粘贴到你的网站。', + 'clipboard_iframe' => '复制嵌入播放器到剪贴板', + 'clipboard_url' => '复制地址到剪贴板', + 'dark' => '暗色', + 'dark-transparent' => '暗色透明', + 'light' => '亮色', + 'light-transparent' => '亮色透明', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/zh-hans/EpisodeNavigation.php b/modules/Admin/Language/zh-hans/EpisodeNavigation.php new file mode 100644 index 00000000..6e6e320d --- /dev/null +++ b/modules/Admin/Language/zh-hans/EpisodeNavigation.php @@ -0,0 +1,23 @@ + '查看剧集页面', + 'dashboard' => '剧集控制面板', + 'episode-view' => '主页', + 'episode-edit' => '编辑剧集', + 'episode-persons-manage' => '管理员', + 'embed-add' => '嵌入式播放器', + 'clips' => '素材', + 'video-clips-list' => '视频素材', + 'video-clips-create' => '新建视频素材', + 'soundbites-list' => '原声摘要', + 'soundbites-create' => '新建原声摘要', +]; diff --git a/modules/Admin/Language/zh-hans/Fediverse.php b/modules/Admin/Language/zh-hans/Fediverse.php new file mode 100644 index 00000000..10d172d2 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => '无法找到此帐户!', + 'blockActorSuccess' => '{actor} 已被封禁!', + 'unblockActorSuccess' => '该用户已被解除封禁', + 'blockDomainSuccess' => '{domain} 已被封禁!', + 'unblockDomainSuccess' => '{domain} 已解除封禁。', + ], + 'blocked_actors' => '已屏蔽帐户', + 'blocked_domains' => '已屏蔽域名', + 'block_lists_form' => [ + 'handle' => '帐户名称', + 'handle_hint' => '输入 @username@domain 帐户。', + 'domain' => '域名', + 'submit' => '封禁!', + ], + 'list' => [ + 'actor' => '帐户', + 'domain' => '域名', + 'unblock' => '解除封禁', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Home.php b/modules/Admin/Language/zh-hans/Home.php new file mode 100644 index 00000000..291e6d3b --- /dev/null +++ b/modules/Admin/Language/zh-hans/Home.php @@ -0,0 +1,14 @@ + '全部播客', + 'no_podcast' => '没有找到播客', +]; diff --git a/modules/Admin/Language/zh-hans/Install.php b/modules/Admin/Language/zh-hans/Install.php new file mode 100644 index 00000000..0c86dcab --- /dev/null +++ b/modules/Admin/Language/zh-hans/Install.php @@ -0,0 +1,61 @@ + '手动配置', + 'manual_config_subtitle' => + '创建一个带有你设置的“.env”文件,并刷新页面以继续安装。', + 'form' => [ + 'instance_config' => '实例配置', + 'hostname' => '主机名', + 'media_base_url' => '媒体基础 URL', + 'media_base_url_hint' => + '如果你使用 CDN 和/或外部分析服务,可以在此处设置它们。', + 'admin_gateway' => '管理网关', + 'admin_gateway_hint' => + '访问管理区域的路由(例如,https://example.com/cp-admin)。默认设置为 cp-admin,处于安全原因,我们建议你修改它。', + 'auth_gateway' => '认证网关', + 'auth_gateway_hint' => + '访问认证页面的路由(例如,https://example.com/cp-auth)。默认设置为 cp-auth,处于安全原因,我们建议你修改它。', + 'database_config' => '数据库配置', + 'database_config_hint' => + 'Castopod 需要连接到你的 MySQL (or MariaDB) 数据库。如果你没有这些所需信息,请联系你的服务器管理员。', + 'db_hostname' => '数据库主机', + 'db_name' => '数据库名', + 'db_username' => '数据库用户名', + 'db_password' => '数据库密码', + 'db_prefix' => '数据库前缀', + 'db_prefix_hint' => + "Castopod 表名的前缀,如果您不知道它的含义,请保持默认。", + 'cache_config' => '缓存配置', + 'cache_config_hint' => + '选择你喜欢的缓存处理程序。如果你不知道它的含义,请保留默认值。', + 'cache_handler' => '缓存处理方法', + 'cacheHandlerOptions' => [ + 'file' => '文件', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => '下一步', + 'submit' => '完成安装', + 'create_superadmin' => '创建你的超级管理员帐户', + 'email' => '邮箱', + 'username' => '用户名', + 'password' => '密码', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + '你的超级管理员帐户已创建。登录开始播客!', + 'databaseConnectError' => + 'Castopod 无法连接到你的数据库。编辑你的数据库配置,然后重试。', + 'writeError' => + "无法创建或写入 `.env` 文件。你必须手动按照 Castopod 中的 `.env.example` 文件模板创建它。", + ], +]; diff --git a/modules/Admin/Language/zh-hans/Navigation.php b/modules/Admin/Language/zh-hans/Navigation.php new file mode 100644 index 00000000..3ed1fccc --- /dev/null +++ b/modules/Admin/Language/zh-hans/Navigation.php @@ -0,0 +1,44 @@ + '切换侧边栏', + 'go_to_website' => '访问网站', + 'go_to_admin' => '登录到管理员', + 'not-authorized' => 'Not authorized', + 'dashboard' => '控制面板', + 'admin' => '主页', + 'podcasts' => '播客', + 'podcast-list' => '全部播客', + 'podcast-create' => '新播客', + 'all-podcast-imports' => '全部播客导入', + 'podcast-imports-add' => '导入播客', + 'persons' => '人员', + 'person-list' => '所有人', + 'person-create' => '新成员', + 'fediverse' => '联邦宇宙', + 'fediverse-blocked-actors' => '已屏蔽帐户', + 'fediverse-blocked-domains' => '已屏蔽域名', + 'users' => '用户', + 'user-list' => '所有用户', + 'user-create' => '新用户', + 'pages' => '其他页面', + 'page-list' => '所有页面', + 'page-create' => '新建页面', + 'settings' => '设置', + 'settings-general' => '通用', + 'settings-theme' => '主题', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => '我的帐户', + 'change-password' => '修改密码', + 'logout' => '注销', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Notifications.php b/modules/Admin/Language/zh-hans/Notifications.php new file mode 100644 index 00000000..aae04819 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Notifications.php @@ -0,0 +1,19 @@ + '通知', + 'reply' => '{actor_username} 回复了你的帖子', + 'favourite' => '{actor_username} 喜欢了你的帖子', + 'reblog' => '{actor_username} 分享了你的帖子', + 'follow' => '{actor_username} 开始关注你', + 'no_notifications' => '没有通知', + 'mark_all_as_read' => '全部标记为已读', +]; diff --git a/modules/Admin/Language/zh-hans/Page.php b/modules/Admin/Language/zh-hans/Page.php new file mode 100644 index 00000000..845da7d0 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Page.php @@ -0,0 +1,30 @@ + '返回主页', + 'page' => '页面', + 'all_pages' => '所有页面', + 'create' => '新建页面', + 'go_to_page' => '转到页面', + 'edit' => '编辑页面', + 'delete' => '删除页面', + 'form' => [ + 'title' => '标题', + 'permalink' => '永久链接', + 'content' => '内容', + 'submit_create' => '创建页面', + 'submit_edit' => '保存', + ], + 'messages' => [ + 'createSuccess' => '页面 “{pageTitle}” 已创建!', + 'editSuccess' => '页面已更新!', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Pager.php b/modules/Admin/Language/zh-hans/Pager.php new file mode 100644 index 00000000..3abbc583 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Pager.php @@ -0,0 +1,21 @@ + '页面导航', + 'first' => '首页', + 'previous' => '上一个', + 'next' => '下一页', + 'last' => '上一页', + 'older' => '年长者', + 'newer' => '新人', + 'invalidTemplate' => '{0} 不是有效的分页模板。', + 'invalidPaginationGroup' => '{0} 不是有效的分页组。', +]; diff --git a/modules/Admin/Language/zh-hans/Person.php b/modules/Admin/Language/zh-hans/Person.php new file mode 100644 index 00000000..80243c1d --- /dev/null +++ b/modules/Admin/Language/zh-hans/Person.php @@ -0,0 +1,65 @@ + '人', + 'all_persons' => '所有人', + 'no_person' => '未找到该用户!', + 'create' => '创建人员', + 'view' => '查看人员', + 'edit' => '编辑人员', + 'delete' => '删除人员', + 'messages' => [ + 'createSuccess' => '人员已创建!', + 'editSuccess' => '人员已更新!', + 'deleteSuccess' => '人员已被删除!', + ], + 'form' => [ + 'avatar' => '头像', + 'avatar_size_hint' => + '头像必须是方形,而且至少 400 px 宽度和高度。', + 'full_name' => '全名', + 'full_name_hint' => '这是此人的全名或别名。', + 'unique_name' => '唯一名称', + 'unique_name_hint' => '用于 URL', + 'information_url' => '信息 URL', + 'information_url_hint' => + '指向此人的相关信息资源的 Url,例如主页或第三方个人资料平台。', + 'submit_create' => '创建人员', + 'submit_edit' => '保存人员', + ], + 'podcast_form' => [ + 'title' => '管理人员', + 'add_section_title' => '添加此人到播客中', + 'add_section_subtitle' => '你可以选择几个人和他们的角色。', + 'persons' => '人', + 'persons_hint' => + '你可以选择一个或多个具有相同角色的人。 但需要先创建人。', + 'roles' => '角色', + 'roles_hint' => + '你可以为一个人选择零、一个或多个角色。', + 'submit_add' => '添加人员', + 'remove' => '移除', + ], + 'episode_form' => [ + 'title' => '管理人员', + 'add_section_title' => '添加人到此剧集', + 'add_section_subtitle' => '你可以选择几个人和他们的角色。', + 'persons' => '人', + 'persons_hint' => + '你可以选择一个或多个具有相同角色的人。 但需要先创建人。', + 'roles' => '角色', + 'roles_hint' => + '你可以为一个人选择零、一个或多个角色。', + 'submit_add' => '添加人员', + 'remove' => '移除', + ], + 'credits' => '鸣谢', +]; diff --git a/modules/Admin/Language/zh-hans/Platforms.php b/modules/Admin/Language/zh-hans/Platforms.php new file mode 100644 index 00000000..2869a4b2 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => '转至 {platformName} 网站', + 'register' => 'Register', + 'submit_url' => '在 {platformName} 上提交你的播客', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => '在播客主页上显示?', + 'on_embed' => '在嵌入式播放器上显示?', + 'remove' => '移除 {platformName}', + 'submit' => '保存', + 'messages' => [ + 'updateSuccess' => '平台链接已更新!', + 'removeLinkSuccess' => '平台链接已被移除。', + 'removeLinkError' => + '无法删除平台链接。 再试一次。', + ], + 'description' => [ + 'podcasting' => '此平台上的播客 ID', + 'social' => '此平台上的播客账号ID', + 'funding' => '号召口号', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Podcast.php b/modules/Admin/Language/zh-hans/Podcast.php new file mode 100644 index 00000000..1a47c363 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Podcast.php @@ -0,0 +1,330 @@ + '全部播客', + 'no_podcast' => '没有找到播客!', + 'create' => '创建播客', + 'import' => '导入播客', + 'all_imports' => '播客导入', + 'new_episode' => '新剧集', + 'view' => '浏览博客', + 'edit' => '编辑播客', + 'publish' => '发布播客', + 'publish_edit' => '编辑发布', + 'delete' => '删除播客', + 'see_episodes' => '查看剧集', + 'see_contributors' => '查看贡献者', + 'monetization_other' => 'Other monetization', + 'go_to_page' => '转到页面', + 'latest_episodes' => '最新剧集', + 'see_all_episodes' => '查看所有剧集', + 'draft' => '草稿', + 'messages' => [ + 'createSuccess' => '播客创建成功!', + 'editSuccess' => '播客已更新!', + 'importSuccess' => '播客已导入!', + 'deleteSuccess' => '播客 @{podcast_handle} 已删除!', + 'deletePodcastMediaError' => '删除播客失败 {type, select, + cover {封面} + banner {横幅} + other {媒体} + }', + 'deleteEpisodeMediaError' => '无法删除博客剧集 {episode_slug} {type, select, + transcript {字幕} + chapters {章节} + image {封面} + audio {音频} + other {媒体} + }。', + 'deletePodcastMediaFolderError' => '无法删除播客媒体文件夹 {folder_path}。 你可以手动将其从磁盘中删除。', + 'podcastFeedUpdateSuccess' => '成功更新:{number_of_new_episodes, plural, + one {#剧集} + other {# 剧集} + } 添加到播客!', + 'podcastFeedUpToDate' => '播客已经是最新状态。', + 'publishError' => '此播客已经发布或计划发布。', + 'publishEditError' => '此播客未计划发布。', + 'publishCancelSuccess' => '取消播客发布!', + 'scheduleDateError' => '计划日期必须设置!', + ], + 'form' => [ + 'identity_section_title' => '播客标识', + 'identity_section_subtitle' => '这些字段可能让你脱颖而出。', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => '播客封面', + 'cover_size_hint' => '封面必须是方形,而且至少 1400 px 宽度和高度。', + 'banner' => '播客横幅', + 'banner_size_hint' => '横幅必须有 3:1 比例,宽度至少为 1500px。', + 'banner_delete' => '删除播客横幅', + 'title' => '标题', + 'handle' => '标头', + 'handle_hint' => + '用于识别播客。允许使用大小写、数字和下划线。', + 'type' => [ + 'label' => '类型', + 'episodic' => '剧集', + 'episodic_hint' => '如果在没有任何特定情况下进行剧集排序。那么最新剧集优先显示。', + 'serial' => '系列', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => '描述', + 'classification_section_title' => '分类', + 'classification_section_subtitle' => + '这些字段将影响你的受众。', + 'language' => '切换语言', + 'category' => '类别', + 'category_placeholder' => '选择分类...', + 'other_categories' => '其他分类', + 'parental_advisory' => [ + 'label' => '警告标记', + 'hint' => '是否包含限制级内容?', + 'undefined' => '未定义', + 'clean' => '重置为默认', + 'explicit' => '限制级', + ], + 'author_section_title' => '作者', + 'author_section_subtitle' => '谁在管理播客?', + 'owner_name' => '所有者名称', + 'owner_name_hint' => + '仅供管理使用,在公开 RSS 摘要中可见。', + 'owner_email' => '所有者邮箱', + 'owner_email_hint' => + '大多数平台将使用它来验证播客的所有权。 在公开 RSS 摘要中可见。', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => '发布者', + 'publisher_hint' => + '负责制作节目的小组。 通常指播客的母公司或网络。 有时会被标记为“作者”。', + 'copyright' => '版权', + 'location_section_title' => '地点', + 'location_section_subtitle' => '这个播客在哪里?', + 'location_name' => '位置名称或地址', + 'location_name_hint' => '真或假的地方都可以', + 'monetization_section_title' => '货币化', + 'monetization_section_subtitle' => + '感谢你的听众支持。', + 'premium' => '高级版', + 'premium_by_default' => '剧集必须默认设置为付费会员订阅。', + 'premium_by_default_hint' => '默认情况下,播客剧集将被标记为高级。 你仍然可以选择将某些剧集、预告片等设置为公开。', + 'op3' => '打开播客前缀项目 (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => '使用 OP3(一项开源且值得信赖的第三方分析服务)来评估您的分析数据。 与开源播客生态系统共享、验证和比较您的分析数据。', + 'op3_enable' => '启用 OP3 分析服务', + 'op3_enable_hint' => '出于安全原因,高级剧集的分析数据将不会与 OP3 共享。', + 'payment_pointer' => '网络货币化支付指南', + 'payment_pointer_hint' => + '借助网络货币化,你可以在此收款', + 'advanced_section_title' => '高级参数', + 'advanced_section_subtitle' => + '如果您需要 Castopod 无法处理的 RSS 标签,请在此处设置它们。', + 'custom_rss' => '播客的自定义 RSS 标签', + 'custom_rss_hint' => '这将被注入到 ❬channel❭ 标签中。', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => '新摘要网址', + 'new_feed_url_hint' => '当你迁移到另一个域或播客托管平台时,请使用此字段。 默认情况下,播客导入时,该值为当前的 RSS 网址。', + 'old_feed_url' => '旧摘要网址', + 'partnership' => '合作伙伴', + 'partner_id' => 'ID', + 'partner_link_url' => '链接网址', + 'partner_image_url' => '图片网址', + 'partner_id_hint' => '你自己的合作伙伴 ID', + 'partner_link_url_hint' => '通用合作伙伴链接地址', + 'partner_image_url_hint' => '通用合作伙伴图片地址', + 'block' => '播客应该在公共目录中隐藏', + 'block_hint' => + '播客显示或隐藏状态:打开此选项可防止整个播客出现在 Apple 播客、Google 播客以及从此目录中提取剧集的任何第三方应用程序中。(不保证)', + 'complete' => '播客没有新剧集', + 'lock' => '防止播客被盗用', + 'lock_hint' => + '目的是告诉其他播客平台是否允许导入此摘要。 值为是表示拒绝将此摘要导入任何平台。', + 'submit_create' => '创建播客', + 'submit_edit' => '保存播客', + ], + 'category_options' => [ + 'uncategorized' => '未分类', + 'arts' => '艺术', + 'business' => '商业', + 'comedy' => '喜剧', + 'education' => '教育', + 'fiction' => '小说', + 'government' => '政府', + 'health_and_fitness' => '健康和健身', + 'history' => '历史', + 'kids_and_family' => '儿童与家庭', + 'leisure' => '休闲娱乐', + 'music' => '音乐', + 'news' => '新闻', + 'religion_and_spirituality' => '宗教与精神', + 'science' => '科学', + 'society_and_culture' => '社会与文化', + 'sports' => '体育运动', + 'technology' => '技术', + 'true_crime' => '真实犯罪', + 'tv_and_film' => '电视与电影', + 'books' => '图书', + 'design' => '设计', + 'fashion_and_beauty' => '时尚与美容', + 'food' => '美食', + 'performing_arts' => '表演艺术', + 'visual_arts' => '视觉艺术', + 'careers' => '职业生涯', + 'entrepreneurship' => '创业', + 'investing' => '金融投资', + 'management' => '管理', + 'marketing' => '市场营销', + 'non_profit' => '非盈利活动', + 'comedy_interviews' => '喜剧采访', + 'improv' => '即兴表演', + 'stand_up' => '单口相声', + 'courses' => '课程', + 'how_to' => '动手能力', + 'language_learning' => '语言学习', + 'self_improvement' => '自我提升', + 'comedy_fiction' => '喜剧小说', + 'drama' => '戏剧', + 'science_fiction' => '科幻', + 'alternative_health' => '保健', + 'fitness' => '健身', + 'medicine' => '医学', + 'mental_health' => '心理健康', + 'nutrition' => '营养学', + 'sexuality' => '性', + 'education_for_kids' => '儿童教育', + 'parenting' => '育儿', + 'pets_and_animals' => '宠物与动物', + 'stories_for_kids' => '童话故事', + 'animation_and_manga' => '动漫', + 'automotive' => '汽车', + 'aviation' => '航空', + 'crafts' => '工艺', + 'games' => '游戏', + 'hobbies' => '兴趣爱好', + 'home_and_garden' => '家居与园艺', + 'video_games' => '电子游戏', + 'music_commentary' => '音乐评论', + 'music_history' => '音乐史', + 'music_interviews' => '音乐采访', + 'business_news' => '商业新闻', + 'daily_news' => '每日新闻', + 'entertainment_news' => '娱乐新闻', + 'news_commentary' => '新闻评论', + 'politics' => '政治', + 'sports_news' => '体育新闻', + 'tech_news' => '科技新闻', + 'buddhism' => '佛教', + 'christianity' => '基督教', + 'hinduism' => '印度教', + 'islam' => '伊斯兰教', + 'judaism' => '犹太教', + 'religion' => '宗教信仰', + 'spirituality' => '精神生活', + 'astronomy' => '天文学', + 'chemistry' => '化学', + 'earth_sciences' => '地球科学', + 'life_sciences' => '生命科学', + 'mathematics' => '数学', + 'natural_sciences' => '自然科学', + 'nature' => '自然', + 'physics' => '物理学', + 'social_sciences' => '社会科学', + 'documentary' => '纪实', + 'personal_journals' => '个人日记', + 'philosophy' => '哲学', + 'places_and_travel' => '地方与旅行', + 'relationships' => '人际关系', + 'baseball' => '棒球', + 'basketball' => '篮球', + 'cricket' => '板球', + 'fantasy_sports' => '梦幻体育', + 'football' => '足球', + 'golf' => '高尔夫球', + 'hockey' => '曲棍球', + 'rugby' => '橄榄球', + 'running' => '跑步', + 'soccer' => '英式足球', + 'swimming' => '游泳', + 'tennis' => '网球', + 'volleyball' => '排球', + 'wilderness' => '荒野', + 'wrestling' => '摔跤', + 'after_shows' => '幕后', + 'film_history' => '电影史', + 'film_interviews' => '电影采访', + 'film_reviews' => '电影评论', + 'tv_reviews' => '电视评论', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => '返回播客控制面板', + 'post' => '你的公告播文', + 'post_hint' => + "写一条消息来宣布您的播客发布。该消息将在您的播客主页中显示。", + 'message_placeholder' => '写下你的消息…', + 'submit' => '发布', + 'publication_date' => '发布日期', + 'publication_method' => [ + 'now' => '现在', + 'schedule' => '计划', + ], + 'scheduled_publication_date' => '计划发布日期', + 'scheduled_publication_date_hint' => + '你可以通过设置未来发布日期来安排播客发布。此字段必须格式为 YYYY-MM-DD HH:mm', + 'submit_edit' => '编辑发布', + 'cancel_publication' => '取消发布', + 'message_warning' => '你没有为你的公告播文写一条消息!', + 'message_warning_hint' => '有消息发送可以增加社交参与度,从而提高你的播客曝光度。', + 'message_warning_submit' => '仍然发布', + ], + 'publication_status_banner' => [ + 'draft_mode' => '草稿模式', + 'not_published' => '该播客尚未发布。', + 'scheduled' => '该播客计划在 {publication_date} 发布。', + ], + 'delete_form' => [ + 'disclaimer' => + "删除播客将删除相关的所有剧集、媒体文件、帖子和分析。 此操作不可逆,无法恢复。", + 'understand' => '我明白,我希望永久删除播客。', + 'submit' => '删除', + ], + 'by' => '由 {publisher} 推出', + 'season' => '第 {seasonNumber} 季', + 'list_of_episodes_year' => '{year} 剧集 ({episodeCount})', + 'list_of_episodes_season' => + '第 {seasonNumber} 季(第 {episodeCount} 集)', + 'no_episode' => '没有找到剧集!', + 'follow' => '关注', + 'followers' => '{numberOfFollowers, plural, + one {# 关注者} + other {#关注者} + }', + 'posts' => '{numberOfPosts, plural, + one {# 帖子} + other {# 帖子} + }', + 'activity' => '活动', + 'episodes' => '剧集', + 'sponsor' => '赞助者', + 'funding_links' => '{podcastTitle} 的捐助链接', + 'find_on' => '找到 {podcastTitle} 在', + 'listen_on' => '收听', +]; diff --git a/modules/Admin/Language/zh-hans/PodcastNavigation.php b/modules/Admin/Language/zh-hans/PodcastNavigation.php new file mode 100644 index 00000000..0978a9b2 --- /dev/null +++ b/modules/Admin/Language/zh-hans/PodcastNavigation.php @@ -0,0 +1,42 @@ + '转到播客页面', + 'rss_feed' => 'RSS feed', + 'dashboard' => '播客控制面板', + 'podcast-view' => '主页', + 'podcast-edit' => '编辑播客', + 'podcast-persons-manage' => '管理人员', + 'podcast-imports' => '播客导入', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => '剧集', + 'episode-list' => '所有剧集', + 'episode-create' => '新剧集', + 'analytics' => '统计数据', + 'podcast-analytics' => '听众概览', + 'podcast-analytics-webpages' => '网页访问', + 'podcast-analytics-locations' => '位置信息', + 'podcast-analytics-unique-listeners' => '独特听众', + 'podcast-analytics-players' => '播放', + 'podcast-analytics-listening-time' => '收听时间', + 'podcast-analytics-time-periods' => '时间段', + 'monetization' => 'Monetization', + 'subscription-list' => '所有订阅', + 'subscription-create' => 'Add subscription', + 'contributors' => '贡献者', + 'contributor-list' => '所有贡献者', + 'contributor-add' => '添加贡献者', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => '社交网络', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/zh-hans/Settings.php b/modules/Admin/Language/zh-hans/Settings.php new file mode 100644 index 00000000..10875b1e --- /dev/null +++ b/modules/Admin/Language/zh-hans/Settings.php @@ -0,0 +1,58 @@ + '常用设置', + 'instance' => [ + 'title' => '实例', + 'site_icon' => '站点图标', + 'site_icon_delete' => '删除站点图标', + 'site_icon_hint' => '站点图标是您在浏览器标签页、书签栏及将网站添加为移动设备上的快捷方式时看到的内容。', + 'site_icon_helper' => '图标必须是方形,而且至少 512px 宽度和高度。', + 'site_name' => '站点名称', + 'site_description' => '站点描述', + 'submit' => '保存', + 'editSuccess' => '实例已更新!', + 'deleteIconSuccess' => '站点图标已移除!', + ], + 'images' => [ + 'title' => '图像', + 'subtitle' => '在这里,你可以根据上传的原始图像重新生成所有图像。 如果发现某些图像丢失,请使用此项功能。此功能可能需要执行一段时间。', + 'regenerate' => '重新生成图片', + 'regenerationSuccess' => '所有图片已重新生成!', + ], + 'housekeeping' => [ + 'title' => '维护任务', + 'subtitle' => '运行维护任务。如果遇到媒体文件或数据丢失,请使用此功能。这些任务可能需要一段时间。', + 'reset_counts' => '重置计数', + 'reset_counts_helper' => '此选项将重新计算并重置所有数据统计(关注者数目、帖子、评论、 …)。', + 'rewrite_media' => '重写媒体元数据', + 'rewrite_media_helper' => '此选项将删除所有多余的媒体文件并重新创建(图像、音频、字幕、章节、 …)', + 'rename_episodes_files' => '重命名剧集音频文件', + 'rename_episodes_files_hint' => '此选项会将所有剧集音频文件重命名为随机字符串。 如果你的私人剧集链接被泄露,使用此选项可以隐藏。', + 'clear_cache' => '清除所有缓存', + 'clear_cache_helper' => '此选项将从可写/缓存文件夹中删除整个 redis 缓存或缓存文件。', + 'run' => '运行维护任务', + 'runSuccess' => '维护成功!', + ], + 'theme' => [ + 'title' => '主题', + 'accent_section_title' => '主题色', + 'accent_section_subtitle' => '选择一个颜色来确定所有公共页面的外观体验。', + 'pine' => '松色', + 'crimson' => '绯红', + 'amber' => '琥珀', + 'lake' => '湖色', + 'jacaranda' => '蓝花楹', + 'onyx' => '黑玛瑙色', + 'submit' => '保存', + 'setInstanceThemeSuccess' => '主题已更新!', + ], +]; diff --git a/modules/Admin/Language/zh-hans/Soundbite.php b/modules/Admin/Language/zh-hans/Soundbite.php new file mode 100644 index 00000000..4d5f02d9 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => '原声摘要', + 'soundbite' => '原声摘要', + ], + 'messages' => [ + 'createSuccess' => '原声摘要已创建!', + 'deleteSuccess' => '原声摘要已移除!', + ], + 'form' => [ + 'title' => '新原声摘要', + 'soundbite_title' => '原声摘要标题', + 'start_time' => '开始于', + 'duration' => '持续时间', + 'submit' => '创建原声摘要', + ], + 'play' => '播放原声摘要', + 'stop' => '停止原声摘要', + 'create' => '新原声摘要', + 'delete' => '删除原声摘要', +]; diff --git a/modules/Admin/Language/zh-hans/Validation.php b/modules/Admin/Language/zh-hans/Validation.php new file mode 100644 index 00000000..4a447d44 --- /dev/null +++ b/modules/Admin/Language/zh-hans/Validation.php @@ -0,0 +1,17 @@ + + '{field} 不是一张图片,或者宽或高度不够。', + 'is_image_ratio' => + '{field} 不是图片或比例不正确。', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/zh-hans/VideoClip.php b/modules/Admin/Language/zh-hans/VideoClip.php new file mode 100644 index 00000000..45f80b6b --- /dev/null +++ b/modules/Admin/Language/zh-hans/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => '视频素材', + 'status' => [ + 'label' => '状态', + 'queued' => '队列', + 'queued_hint' => '素材正在等待处理。', + 'pending' => '待处理', + 'pending_hint' => '素材将很快完成。', + 'running' => '运行中', + 'running_hint' => '正在生成素材。', + 'failed' => '已失败', + 'failed_hint' => '无法生成素材:脚本运行失败。', + 'passed' => '已通过', + 'passed_hint' => '素材生成成功!', + ], + 'clip' => '素材', + 'duration' => '工作时间', + ], + 'title' => '视频素材: {videoClipLabel}', + 'download_clip' => '下载素材', + 'create' => '新建视频素材', + 'go_to_page' => '跳转到素材页面', + 'retry' => '重试素材生成', + 'delete' => '删除素材', + 'logs' => '任务日志', + 'messages' => [ + 'alreadyExistingError' => '你尝试创建的视频素材已存在!', + 'addToQueueSuccess' => '视频素材已添加到队列中,等待创建!', + 'deleteSuccess' => '已删除视频素材', + ], + 'format' => [ + 'landscape' => '横向', + 'portrait' => '竖屏', + 'squared' => '方形', + ], + 'form' => [ + 'title' => '新建视频素材', + 'params_section_title' => '视频素材参数', + 'clip_title' => '素材标题', + 'format' => [ + 'label' => '选择格式', + 'landscape_hint' => '使用 16:9的比例,非常适合 PeerTube、Youtube 和 Vimeo。', + 'portrait_hint' => '使用 9:16 的比例,非常适合 TikTok,Youtube shorts 和 Instagram。', + 'squared_hint' => '使用 1:1的比例,非常适合 Mastodon、Facebook、Twitter 和 LinkedIn。', + ], + 'theme' => '选择主题', + 'start_time' => '开始于', + 'duration' => '持续时间', + 'trim_start' => '修剪开始', + 'trim_end' => '修剪结束', + 'submit' => '创建视频素材', + ], + 'requirements' => [ + 'title' => '未达到要求', + 'missing' => '你有未达到的要求。 添加所有必需项才能为此剧集创建视频!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'GD 的 Freetype 库', + 'transcript' => '字幕文件(.srt)', + ], +]; diff --git a/modules/Admin/Language/zh-hant/AboutCastopod.php b/modules/Admin/Language/zh-hant/AboutCastopod.php new file mode 100644 index 00000000..3fb62aff --- /dev/null +++ b/modules/Admin/Language/zh-hant/AboutCastopod.php @@ -0,0 +1,22 @@ + 'About Castopod', + 'host_name' => 'Host name', + 'version' => 'Castopod version', + 'php_version' => 'PHP version', + 'os' => 'Operating System', + 'languages' => 'Languages', + 'update_database' => 'Update database', + 'messages' => [ + 'databaseUpdateSuccess' => 'Database is up to date!', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Breadcrumb.php b/modules/Admin/Language/zh-hant/Breadcrumb.php new file mode 100644 index 00000000..408c9f9f --- /dev/null +++ b/modules/Admin/Language/zh-hant/Breadcrumb.php @@ -0,0 +1,57 @@ + 'breadcrumb', + config('Admin') + ->gateway => 'Home', + 'podcasts' => 'podcasts', + 'episodes' => 'episodes', + 'subscriptions' => 'subscriptions', + 'contributors' => 'contributors', + 'pages' => 'pages', + 'settings' => 'settings', + 'theme' => 'theme', + 'about' => 'about', + 'add' => 'add', + 'new' => 'new', + 'edit' => 'edit', + 'persons' => 'persons', + 'publish' => 'publish', + 'publish-edit' => 'edit publication', + 'publish-date-edit' => 'edit publication date', + 'unpublish' => 'unpublish', + 'delete' => 'delete', + 'remove' => 'remove', + 'fediverse' => 'fediverse', + 'blocked-actors' => 'blocked actors', + 'blocked-domains' => 'blocked domains', + 'users' => 'users', + 'my-account' => 'my account', + 'change-password' => 'change password', + 'imports' => 'imports', + 'sync-feeds' => 'synchronize feeds', + 'platforms' => 'platforms', + 'social' => 'social networks', + 'funding' => 'funding', + 'monetization-other' => 'other monetization', + 'analytics' => 'analytics', + 'locations' => 'locations', + 'webpages' => 'web pages', + 'unique-listeners' => 'unique listeners', + 'players' => 'players', + 'listening-time' => 'listening time', + 'time-periods' => 'time periods', + 'soundbites' => 'soundbites', + 'video-clips' => 'video clips', + 'embed' => 'embeddable player', + 'notifications' => 'notifications', + 'suspend' => 'suspend', +]; diff --git a/modules/Admin/Language/zh-hant/Charts.php b/modules/Admin/Language/zh-hant/Charts.php new file mode 100644 index 00000000..6ede2510 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Charts.php @@ -0,0 +1,41 @@ + 'Episode downloads by service (for the past week)', + 'by_player_weekly' => 'Episode downloads by player (for the past week)', + 'by_player_yearly' => 'Episode downloads by player (for the past year)', + 'by_device_weekly' => 'Episode downloads by device (for the past week)', + 'by_os_weekly' => 'Episode downloads by O.S. (for the past week)', + 'podcast_by_region' => 'Episode downloads by region (for the past week)', + 'unique_daily_listeners' => 'Daily unique listeners', + 'unique_monthly_listeners' => 'Monthly unique listeners', + 'by_browser' => 'Web pages usage by browser (for the past week)', + 'podcast_by_day' => 'Episode daily downloads', + 'podcast_by_month' => 'Episode monthly downloads', + 'episode_by_day' => 'Episode daily downloads (first 60 days)', + 'episode_by_month' => 'Episode monthly downloads', + 'episodes_by_day' => + '5 latest episodes downloads (during their first 60 days)', + 'by_country_weekly' => 'Episode downloads by country (for the past week)', + 'by_country_yearly' => 'Episode downloads by country (for the past year)', + 'by_domain_weekly' => 'Web pages visits by source (for the past week)', + 'by_domain_yearly' => 'Web pages visits by source (for the past year)', + 'by_entry_page' => 'Web pages visits by landing page (for the past week)', + 'podcast_bots' => 'Bots (crawlers)', + 'daily_listening_time' => 'Daily cumulative listening time', + 'monthly_listening_time' => 'Monthly cumulative listening time', + 'by_weekday' => 'By week day (for the past 60 days)', + 'by_hour' => 'By time of day (for the past 60 days)', + 'podcast_by_bandwidth' => 'Daily used bandwidth (in MB)', + 'total_storage_by_month' => 'Monthly storage (in MB)', + 'total_bandwidth_by_month' => 'Monthly used bandwidth (in MB)', + 'total_bandwidth_by_month_limit' => 'Limited to {totalBandwidth} per month', +]; diff --git a/modules/Admin/Language/zh-hant/Common.php b/modules/Admin/Language/zh-hant/Common.php new file mode 100644 index 00000000..74addcf2 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Common.php @@ -0,0 +1,52 @@ + 'Yes', + 'no' => 'No', + 'cancel' => 'Cancel', + 'optional' => 'Optional', + 'more' => 'More', + 'no_data' => 'No data found!', + 'close' => 'Close', + 'edit' => 'Edit', + 'copy' => 'Copy', + 'copied' => 'Copied!', + 'home' => 'Home', + 'explicit' => 'Explicit', + 'powered_by' => 'Powered by {castopod}', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', + 'go_back' => 'Go back', + 'forms' => [ + 'editor' => [ + 'write' => 'Write', + 'preview' => 'Preview', + 'help' => 'Powered by markdown', + ], + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading…', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], + 'upload_file' => 'Upload a file', + 'remote_url' => 'Remote URL', + 'save' => 'Save', + ], + 'play_episode_button' => [ + 'play' => 'Play', + 'playing' => 'Playing', + ], + 'size_limit' => 'Size limit: {0}.', + 'choose_interact' => 'Choose how to interact', + 'view' => 'View', +]; diff --git a/modules/Admin/Language/zh-hant/Countries.php b/modules/Admin/Language/zh-hant/Countries.php new file mode 100644 index 00000000..4cd5d9c8 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Countries.php @@ -0,0 +1,264 @@ + 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AO' => 'Angola', + 'AQ' => 'Antarctica', + 'AR' => 'Argentina', + 'AS' => 'American Samoa', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Åland Islands', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia and Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BL' => 'Saint Barthélemy', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia, Plurinational State of', + 'BQ' => 'Bonaire, Sint Eustatius and Saba', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BV' => 'Bouvet Island', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos (Keeling) Islands', + 'CD' => 'Congo, the Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo', + 'CH' => 'Switzerland', + 'CI' => "Côte d'Ivoire", + 'CK' => 'Cook Islands', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CW' => 'Curaçao', + 'CX' => 'Christmas Island', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'EH' => 'Western Sahara', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands (Malvinas)', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'United Kingdom', + 'GD' => 'Grenada', + 'GE' => 'Georgia', + 'GF' => 'French Guiana', + 'GG' => 'Guernsey', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'GT' => 'Guatemala', + 'GU' => 'Guam', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IM' => 'Isle of Man', + 'IN' => 'India', + 'IO' => 'British Indian Ocean Territory', + 'IQ' => 'Iraq', + 'IR' => 'Iran, Islamic Republic of', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JE' => 'Jersey', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts and Nevis', + 'KP' => "Korea, Democratic People's Republic of", + 'KR' => 'Korea, Republic of', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => "Lao People's Democratic Republic", + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco', + 'MD' => 'Moldova, Republic of', + 'ME' => 'Montenegro', + 'MF' => 'Saint Martin (French part)', + 'MG' => 'Madagascar', + 'MH' => 'Marshall Islands', + 'MK' => 'Macedonia, the Former Yugoslav Republic of', + 'ML' => 'Mali', + 'MM' => 'Myanmar', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MP' => 'Northern Mariana Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'N/A' => 'Not Applicable (local IP…)', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NF' => 'Norfolk Island', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NU' => 'Niue', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn', + 'PR' => 'Puerto Rico', + 'PS' => 'Palestine, State of', + 'PT' => 'Portugal', + 'PW' => 'Palau', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Réunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russian Federation', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', + 'SI' => 'Slovenia', + 'SJ' => 'Svalbard and Jan Mayen', + 'SK' => 'Slovakia', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'SS' => 'South Sudan', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SX' => 'Sint Maarten (Dutch part)', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TF' => 'French Southern Territories', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau', + 'TL' => 'Timor-Leste', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan, Province of China', + 'TZ' => 'Tanzania, United Republic of', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UM' => 'United States Minor Outlying Islands', + 'US' => 'United States', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Holy See (Vatican City State)', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela, Bolivarian Republic of', + 'VG' => 'Virgin Islands, British', + 'VI' => 'Virgin Islands, U.S.', + 'VN' => 'Viet Nam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna', + 'WS' => 'Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', +]; diff --git a/modules/Admin/Language/zh-hant/Dashboard.php b/modules/Admin/Language/zh-hant/Dashboard.php new file mode 100644 index 00000000..881073fd --- /dev/null +++ b/modules/Admin/Language/zh-hant/Dashboard.php @@ -0,0 +1,28 @@ + 'Admin dashboard', + 'welcome_message' => 'Welcome to the admin area!', + 'podcasts' => [ + 'title' => 'Podcasts', + 'not_found' => 'No published podcast', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'episodes' => [ + 'title' => 'Episodes', + 'not_found' => 'No published episode', + 'last_published' => 'Last published on {lastPublicationDate}', + ], + 'storage' => [ + 'title' => 'Storage', + 'subtitle' => '{totalUploaded} out of {totalStorage}', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Episode.php b/modules/Admin/Language/zh-hant/Episode.php new file mode 100644 index 00000000..4fa846e3 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Episode.php @@ -0,0 +1,225 @@ + 'Season {seasonNumber}', + 'season_abbr' => 'S{seasonNumber}', + 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', + 'number_of_comments' => '{numberOfComments, plural, + one {# comment} + other {# comments} + }', + 'all_podcast_episodes' => 'All podcast episodes', + 'back_to_podcast' => 'Go back to podcast', + 'edit' => 'Edit', + 'preview' => 'Preview', + 'publish' => 'Publish', + 'publish_edit' => 'Edit publication', + 'publish_date_edit' => 'Edit publication date', + 'unpublish' => 'Unpublish', + 'publish_error' => 'Episode is already published.', + 'publish_edit_error' => 'Episode is already published.', + 'publish_cancel_error' => 'Episode is already published.', + 'publish_date_edit_error' => 'Episode has not been published yet, you cannot edit its publication date.', + 'publish_date_edit_future_error' => 'Episode\'s publication date can only be set to a past date! If you would like to reschedule it, unpublish it first.', + 'publish_date_edit_success' => 'Episode\'s publication date has been updated successfully!', + 'unpublish_error' => 'Episode is not published.', + 'delete' => 'Delete', + 'go_to_page' => 'Go to page', + 'create' => 'Add an episode', + 'publication_status' => [ + 'published' => 'Published', + 'with_podcast' => 'Published', + 'scheduled' => 'Scheduled', + 'not_published' => 'Not published', + ], + 'with_podcast_hint' => 'To be published at the same time as the podcast', + 'list' => [ + 'search' => [ + 'placeholder' => 'Search for an episode', + 'clear' => 'Clear search', + 'submit' => 'Search', + ], + 'number_of_episodes' => '{numberOfEpisodes, plural, + one {# episode} + other {# episodes} + }', + 'episode' => 'Episode', + 'visibility' => 'Visibility', + 'downloads' => 'Downloads', + 'comments' => 'Comments', + 'actions' => 'Actions', + ], + 'messages' => [ + 'createSuccess' => 'Episode has been successfully created!', + 'editSuccess' => 'Episode has been successfully updated!', + 'publishSuccess' => '{publication_status, select, + published {Episode successfully published!} + scheduled {Episode publication successfully scheduled!} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not published.} + }', + 'publishCancelSuccess' => 'Episode publication successfully cancelled!', + 'unpublishBeforeDeleteTip' => 'You must unpublish the episode before deleting it.', + 'scheduleDateError' => 'Schedule date must be set!', + 'deletePublishedEpisodeError' => 'Please unpublish the episode before deleting it.', + 'deleteSuccess' => 'Episode successfully deleted!', + 'deleteError' => 'Failed to delete episode {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deleteFileError' => 'Failed to delete {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + } file {file_key}. You may manually remove it from your disk.', + 'sameSlugError' => 'An episode with the chosen slug already exists.', + ], + 'form' => [ + 'file_size_error' => + 'Your file size is too big! Max size is {0}. Increase the `memory_limit`, `upload_max_filesize` and `post_max_size` values in your php configuration file then restart your web server to upload your file.', + 'audio_file' => 'Audio file', + 'audio_file_hint' => 'Choose an .mp3 or .m4a audio file.', + 'info_section_title' => 'Episode info', + 'cover' => 'Episode cover', + 'cover_hint' => + 'If you do not set a cover, the podcast cover will be used instead.', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'title' => 'Title', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', + 'permalink' => 'Permalink', + 'season_number' => 'Season', + 'episode_number' => 'Episode', + 'type' => [ + 'label' => 'Type', + 'full' => 'Full', + 'full_hint' => 'Complete content (the episode)', + 'trailer' => 'Trailer', + 'trailer_hint' => 'Short, promotional piece of content that represents a preview of the current show', + 'bonus' => 'Bonus', + 'bonus_hint' => 'Extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show', + ], + 'premium_title' => 'Premium', + 'premium' => 'Episode must be accessible to premium subscribers only', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'additional_files_section_title' => 'Additional files', + 'additional_files_section_subtitle' => + 'These files may be used by other platforms to provide better experience to your audience. See the {podcastNamespaceLink} for more information.', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this episode about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real or fictional location', + 'transcript' => 'Transcript (subtitles / closed captions)', + 'transcript_hint' => 'Only .srt or .vtt are allowed.', + 'transcript_download' => 'Download transcript', + 'transcript_file' => 'Transcript file (.srt or .vtt)', + 'transcript_remote_url' => 'Remote url for transcript', + 'transcript_file_delete' => 'Delete transcript file', + 'chapters' => 'Chapters', + 'chapters_hint' => 'File must be in JSON Chapters format.', + 'chapters_download' => 'Download chapters', + 'chapters_file' => 'Chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', + 'chapters_file_delete' => 'Delete chapters file', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the episode', + 'custom_rss_hint' => 'This will be injected within the ❬item❭ tag.', + 'block' => 'Episode should be hidden from public catalogues', + 'block_hint' => + 'The episode show or hide status: toggling this on prevents the episode from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'submit_create' => 'Create episode', + 'submit_edit' => 'Save episode', + ], + 'publish_form' => [ + 'back_to_episode_dashboard' => 'Back to episode dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your episode. The message will be broadcasted to all your followers in the fediverse and be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + 'with_podcast' => 'Publish alongside podcast', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_clear' => 'Clear publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the episode release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit' => 'Publish', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your episode.', + 'message_warning_submit' => 'Publish anyways', + ], + 'publish_date_edit_form' => [ + 'new_publication_date' => 'New publication date', + 'new_publication_date_hint' => 'Must be set to a past date.', + 'submit' => 'Edit publication date', + ], + 'unpublish_form' => [ + 'disclaimer' => + "Unpublishing the episode will delete all the comments and posts associated with it and remove it from the podcast's RSS feed.", + 'understand' => 'I understand, I want to unpublish the episode', + 'submit' => 'Unpublish', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the episode will delete all media files, comments, video clips and soundbites associated with it.", + 'understand' => 'I understand, I want to delete the episode', + 'submit' => 'Delete', + ], + 'embed' => [ + 'title' => 'Embeddable player', + 'label' => + 'Pick a theme color, copy the embeddable player to clipboard, then paste it on your website.', + 'clipboard_iframe' => 'Copy embeddable player to clipboard', + 'clipboard_url' => 'Copy address to clipboard', + 'dark' => 'Dark', + 'dark-transparent' => 'Dark transparent', + 'light' => 'Light', + 'light-transparent' => 'Light transparent', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'text' => '{publication_status, select, + published {This episode is not yet published.} + scheduled {This episode is scheduled for publication on {publication_date}.} + with_podcast {This episode will be published at the same time as the podcast.} + other {This episode is not yet published.} + }', + 'preview' => 'Preview', + ], +]; diff --git a/modules/Admin/Language/zh-hant/EpisodeNavigation.php b/modules/Admin/Language/zh-hant/EpisodeNavigation.php new file mode 100644 index 00000000..1406e301 --- /dev/null +++ b/modules/Admin/Language/zh-hant/EpisodeNavigation.php @@ -0,0 +1,23 @@ + 'View episode page', + 'dashboard' => 'Episode dashboard', + 'episode-view' => 'Home', + 'episode-edit' => 'Edit episode', + 'episode-persons-manage' => 'Manage persons', + 'embed-add' => 'Embeddable player', + 'clips' => 'Clips', + 'video-clips-list' => 'Video clips', + 'video-clips-create' => 'New video clip', + 'soundbites-list' => 'Soundbites', + 'soundbites-create' => 'New soundbite', +]; diff --git a/modules/Admin/Language/zh-hant/Fediverse.php b/modules/Admin/Language/zh-hant/Fediverse.php new file mode 100644 index 00000000..0e4ca66d --- /dev/null +++ b/modules/Admin/Language/zh-hant/Fediverse.php @@ -0,0 +1,32 @@ + [ + 'actorNotFound' => 'The account could not be found!', + 'blockActorSuccess' => '{actor} has been blocked!', + 'unblockActorSuccess' => 'Actor has been unblocked!', + 'blockDomainSuccess' => '{domain} has been blocked!', + 'unblockDomainSuccess' => '{domain} has been unblocked!', + ], + 'blocked_actors' => 'Blocked accounts', + 'blocked_domains' => 'Blocked domains', + 'block_lists_form' => [ + 'handle' => 'Account handle', + 'handle_hint' => 'Input @username@domain account.', + 'domain' => 'Domain name', + 'submit' => 'Block!', + ], + 'list' => [ + 'actor' => 'Account', + 'domain' => 'Domain name', + 'unblock' => 'Unblock', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Home.php b/modules/Admin/Language/zh-hant/Home.php new file mode 100644 index 00000000..3ff4c04d --- /dev/null +++ b/modules/Admin/Language/zh-hant/Home.php @@ -0,0 +1,14 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found', +]; diff --git a/modules/Admin/Language/zh-hant/Install.php b/modules/Admin/Language/zh-hant/Install.php new file mode 100644 index 00000000..36e373a2 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Install.php @@ -0,0 +1,61 @@ + 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Admin/Language/zh-hant/Navigation.php b/modules/Admin/Language/zh-hant/Navigation.php new file mode 100644 index 00000000..f3ffb129 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Navigation.php @@ -0,0 +1,44 @@ + 'Toggle sidebar', + 'go_to_website' => 'Go to website', + 'go_to_admin' => 'Go to admin', + 'not-authorized' => 'Not authorized', + 'dashboard' => 'Dashboard', + 'admin' => 'Home', + 'podcasts' => 'Podcasts', + 'podcast-list' => 'All podcasts', + 'podcast-create' => 'New podcast', + 'all-podcast-imports' => 'All Podcast imports', + 'podcast-imports-add' => 'Import a podcast', + 'persons' => 'Persons', + 'person-list' => 'All persons', + 'person-create' => 'New person', + 'fediverse' => 'Fediverse', + 'fediverse-blocked-actors' => 'Blocked accounts', + 'fediverse-blocked-domains' => 'Blocked domains', + 'users' => 'Users', + 'user-list' => 'All users', + 'user-create' => 'New user', + 'pages' => 'Pages', + 'page-list' => 'All pages', + 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', + 'settings-theme' => 'Theme', + 'admin-about' => 'About', + 'account' => [ + 'my-account' => 'My account', + 'change-password' => 'Change password', + 'logout' => 'Logout', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Notifications.php b/modules/Admin/Language/zh-hant/Notifications.php new file mode 100644 index 00000000..2b139d51 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Notifications.php @@ -0,0 +1,19 @@ + 'Notifications', + 'reply' => '{actor_username} replied to your post', + 'favourite' => '{actor_username} favourited your post', + 'reblog' => '{actor_username} shared your post', + 'follow' => '{actor_username} started following you', + 'no_notifications' => 'No notifications', + 'mark_all_as_read' => 'Mark all as read', +]; diff --git a/modules/Admin/Language/zh-hant/Page.php b/modules/Admin/Language/zh-hant/Page.php new file mode 100644 index 00000000..b6f49de5 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Page.php @@ -0,0 +1,30 @@ + 'Back to home', + 'page' => 'Page', + 'all_pages' => 'All pages', + 'create' => 'New page', + 'go_to_page' => 'Go to page', + 'edit' => 'Edit page', + 'delete' => 'Delete page', + 'form' => [ + 'title' => 'Title', + 'permalink' => 'Permalink', + 'content' => 'Content', + 'submit_create' => 'Create page', + 'submit_edit' => 'Save', + ], + 'messages' => [ + 'createSuccess' => 'The page “{pageTitle}” was created successfully!', + 'editSuccess' => 'The page was successfully updated!', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Pager.php b/modules/Admin/Language/zh-hant/Pager.php new file mode 100644 index 00000000..e25ee638 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Pager.php @@ -0,0 +1,21 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/modules/Admin/Language/zh-hant/Person.php b/modules/Admin/Language/zh-hant/Person.php new file mode 100644 index 00000000..a652be9f --- /dev/null +++ b/modules/Admin/Language/zh-hant/Person.php @@ -0,0 +1,65 @@ + 'Persons', + 'all_persons' => 'All persons', + 'no_person' => 'Nobody found!', + 'create' => 'Create a person', + 'view' => 'View person', + 'edit' => 'Edit person', + 'delete' => 'Delete person', + 'messages' => [ + 'createSuccess' => 'Person has been successfully created!', + 'editSuccess' => 'Person has been successfully updated!', + 'deleteSuccess' => 'Person has been removed!', + ], + 'form' => [ + 'avatar' => 'Avatar', + 'avatar_size_hint' => + 'Avatar must be squared and at least 400px wide and tall.', + 'full_name' => 'Full name', + 'full_name_hint' => 'This is the full name or alias of the person.', + 'unique_name' => 'Unique name', + 'unique_name_hint' => 'Used for URLs', + 'information_url' => 'Information URL', + 'information_url_hint' => + 'Url to a relevant resource of information about the person, such as a homepage or third-party profile platform.', + 'submit_create' => 'Create person', + 'submit_edit' => 'Save person', + ], + 'podcast_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this podcast', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'episode_form' => [ + 'title' => 'Manage persons', + 'add_section_title' => 'Add persons to this episode', + 'add_section_subtitle' => 'You may pick several persons and roles.', + 'persons' => 'Persons', + 'persons_hint' => + 'You may select one or several persons with the same roles. You need to create the persons first.', + 'roles' => 'Roles', + 'roles_hint' => + 'You may select none, one or several roles for a person.', + 'submit_add' => 'Add person(s)', + 'remove' => 'Remove', + ], + 'credits' => 'Credits', +]; diff --git a/modules/Admin/Language/zh-hant/Platforms.php b/modules/Admin/Language/zh-hant/Platforms.php new file mode 100644 index 00000000..e161181c --- /dev/null +++ b/modules/Admin/Language/zh-hant/Platforms.php @@ -0,0 +1,43 @@ + [ + 'podcasting' => 'Podcasting platforms', + 'social' => 'Social networks', + 'funding' => 'Funding links', + ], + 'website' => 'Website', + 'home_url' => 'Go to {platformName} website', + 'register' => 'Register', + 'submit_url' => 'Submit your podcast on {platformName}', + 'your_link' => 'Your link', + 'your_id' => [ + 'podcasting' => 'Your ID', + 'social' => 'Your ID', + 'funding' => 'Your CTA', + ], + 'your_cta' => 'Your call to action', + 'visible' => 'Display in podcast homepage?', + 'on_embed' => 'Display on embeddable player?', + 'remove' => 'Remove {platformName}', + 'submit' => 'Save', + 'messages' => [ + 'updateSuccess' => 'Platform links have been successfully updated!', + 'removeLinkSuccess' => 'The platform link has been removed.', + 'removeLinkError' => + 'The platform link could not be removed. Try again.', + ], + 'description' => [ + 'podcasting' => 'The podcast ID on this platform', + 'social' => 'The podcast account ID on this platform', + 'funding' => 'Call to action message', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Podcast.php b/modules/Admin/Language/zh-hant/Podcast.php new file mode 100644 index 00000000..ff0daebc --- /dev/null +++ b/modules/Admin/Language/zh-hant/Podcast.php @@ -0,0 +1,330 @@ + 'All podcasts', + 'no_podcast' => 'No podcast found!', + 'create' => 'Create podcast', + 'import' => 'Import podcast', + 'all_imports' => 'Podcast imports', + 'new_episode' => 'New Episode', + 'view' => 'View podcast', + 'edit' => 'Edit podcast', + 'publish' => 'Publish podcast', + 'publish_edit' => 'Edit publication', + 'delete' => 'Delete podcast', + 'see_episodes' => 'See episodes', + 'see_contributors' => 'See contributors', + 'monetization_other' => 'Other monetization', + 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', + 'draft' => 'Draft', + 'messages' => [ + 'createSuccess' => 'Podcast successfully created!', + 'editSuccess' => 'Podcast has been successfully updated!', + 'importSuccess' => 'Podcast has been successfully imported!', + 'deleteSuccess' => 'Podcast @{podcast_handle} successfully deleted!', + 'deletePodcastMediaError' => 'Failed to delete podcast {type, select, + cover {cover} + banner {banner} + other {media} + }.', + 'deleteEpisodeMediaError' => 'Failed to delete podcast episode {episode_slug} {type, select, + transcript {transcript} + chapters {chapters} + image {cover} + audio {audio} + other {media} + }.', + 'deletePodcastMediaFolderError' => 'Failed to delete podcast media folder {folder_path}. You may manually remove it from your disk.', + 'podcastFeedUpdateSuccess' => 'Successful update: {number_of_new_episodes, plural, + one {# episode was} + other {# episodes were} + } added to the podcast!', + 'podcastFeedUpToDate' => 'Podcast is already up to date.', + 'publishError' => 'This podcast is either already published or scheduled for publication.', + 'publishEditError' => 'This podcast is not scheduled for publication.', + 'publishCancelSuccess' => 'Podcast publication successfully cancelled!', + 'scheduleDateError' => 'Schedule date must be set!', + ], + 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'fediverse_section_title' => 'Fediverse identity', + + 'cover' => 'Podcast cover', + 'cover_size_hint' => 'Cover must be squared and at least 1400px wide and tall.', + 'banner' => 'Podcast banner', + 'banner_size_hint' => 'Banner must have a 3:1 ratio and be at least 1500px wide.', + 'banner_delete' => 'Delete podcast banner', + 'title' => 'Title', + 'handle' => 'Handle', + 'handle_hint' => + 'Used to identify the podcast. Uppercase, lowercase, numbers and underscores are accepted.', + 'type' => [ + 'label' => 'Type', + 'episodic' => 'Episodic', + 'episodic_hint' => 'If episodes are intended to be consumed without any specific order. Newest episodes will be presented first.', + 'serial' => 'Serial', + 'serial_hint' => 'If episodes are intended to be consumed in sequential order. Episodes will be presented in numeric order.', + ], + 'medium' => [ + 'label' => 'Medium', + 'hint' => 'Medium as represented by podcast:medium tag in RSS. Changing this may change how players present your feed.', + 'podcast' => 'Podcast', + 'podcast_hint' => 'Describes a feed for a podcast show.', + 'music' => 'Music', + 'music_hint' => 'A feed of music organized into an "album" with each item a song within the album.', + 'audiobook' => 'Audiobook', + 'audiobook_hint' => 'Specific types of audio with one item per feed, or where items represent chapters within the book.', + ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'category_placeholder' => 'Select a category…', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'is_owner_email_removed_from_feed' => 'Remove the owner email from the public RSS feed', + 'is_owner_email_removed_from_feed_hint' => 'You may need to temporarily unhide the email so that a directory can verify your podcast ownership.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'copyright' => 'Copyright', + 'location_section_title' => 'Location', + 'location_section_subtitle' => 'What place is this podcast about?', + 'location_name' => 'Location name or address', + 'location_name_hint' => 'This can be a real place or fictional', + 'monetization_section_title' => 'Monetization', + 'monetization_section_subtitle' => + 'Earn money thanks to your audience.', + 'premium' => 'Premium', + 'premium_by_default' => 'Episodes must be set as premium by default', + 'premium_by_default_hint' => 'Podcast episodes will be marked as premium by default. You can still choose to set some episodes, trailers or bonuses as public.', + 'op3' => 'Open Podcast Prefix Project (OP3)', + 'op3_link' => 'Visit your OP3 dashboard (external link)', + 'op3_hint' => 'Value your analytics data with OP3, an open-source and trusted third party analytics service. Share, validate and compare your analytics data with the open podcasting ecosystem.', + 'op3_enable' => 'Enable OP3 analytics service', + 'op3_enable_hint' => 'For security reasons, premium episodes\' analytics data will not be shared with OP3.', + 'payment_pointer' => 'Payment Pointer for Web Monetization', + 'payment_pointer_hint' => + 'This is your where you will receive money thanks to Web Monetization', + 'advanced_section_title' => 'Advanced Parameters', + 'advanced_section_subtitle' => + 'If you need RSS tags that Castopod does not handle, set them here.', + 'custom_rss' => 'Custom RSS tags for the podcast', + 'custom_rss_hint' => 'This will be injected within the ❬channel❭ tag.', + 'verify_txt' => 'Ownership verification TXT', + 'verify_txt_hint' => 'Rather than relying on email, certain third-party services may confirm your podcast ownership by requesting you to embed a verification text within your feed.', + 'verify_txt_helper' => 'This text is injected into a tag.', + 'new_feed_url' => 'New feed URL', + 'new_feed_url_hint' => 'Use this field when you move to another domain or podcast hosting platform. By default, the value is set to the current RSS URL if the podcast is imported.', + 'old_feed_url' => 'Old feed URL', + 'partnership' => 'Partnership', + 'partner_id' => 'ID', + 'partner_link_url' => 'Link URL', + 'partner_image_url' => 'Image URL', + 'partner_id_hint' => 'Your own partner ID', + 'partner_link_url_hint' => 'The generic partner link address', + 'partner_image_url_hint' => 'The generic partner image address', + 'block' => 'Podcast should be hidden from public catalogues', + 'block_hint' => + 'The podcast show or hide status: toggling this on prevents the entire podcast from appearing in Apple Podcasts, Google Podcasts, and any third party apps that pull shows from these directories. (Not guaranteed)', + 'complete' => 'Podcast will not be having new episodes', + 'lock' => 'Prevent podcast from being copied', + 'lock_hint' => + 'The purpose is to tell other podcast platforms whether they are allowed to import this feed. A value of yes means that any attempt to import this feed into a new platform should be rejected.', + 'submit_create' => 'Create podcast', + 'submit_edit' => 'Save podcast', + ], + 'category_options' => [ + 'uncategorized' => 'uncategorized', + 'arts' => 'Arts', + 'business' => 'Business', + 'comedy' => 'Comedy', + 'education' => 'Education', + 'fiction' => 'Fiction', + 'government' => 'Government', + 'health_and_fitness' => 'Health & Fitness', + 'history' => 'History', + 'kids_and_family' => 'Kids & Family', + 'leisure' => 'Leisure', + 'music' => 'Music', + 'news' => 'News', + 'religion_and_spirituality' => 'Religion & Spirituality', + 'science' => 'Science', + 'society_and_culture' => 'Society & Culture', + 'sports' => 'Sports', + 'technology' => 'Technology', + 'true_crime' => 'True Crime', + 'tv_and_film' => 'TV & Film', + 'books' => 'Books', + 'design' => 'Design', + 'fashion_and_beauty' => 'Fashion & Beauty', + 'food' => 'Food', + 'performing_arts' => 'Performing Arts', + 'visual_arts' => 'Visual Arts', + 'careers' => 'Careers', + 'entrepreneurship' => 'Entrepreneurship', + 'investing' => 'Investing', + 'management' => 'Management', + 'marketing' => 'Marketing', + 'non_profit' => 'Non-Profit', + 'comedy_interviews' => 'Comedy Interviews', + 'improv' => 'Improv', + 'stand_up' => 'Stand-Up', + 'courses' => 'Courses', + 'how_to' => 'How To', + 'language_learning' => 'Language Learning', + 'self_improvement' => 'Self-Improvement', + 'comedy_fiction' => 'Comedy Fiction', + 'drama' => 'Drama', + 'science_fiction' => 'Science Fiction', + 'alternative_health' => 'Alternative Health', + 'fitness' => 'Fitness', + 'medicine' => 'Medicine', + 'mental_health' => 'Mental Health', + 'nutrition' => 'Nutrition', + 'sexuality' => 'Sexuality', + 'education_for_kids' => 'Education for Kids', + 'parenting' => 'Parenting', + 'pets_and_animals' => 'Pets & Animals', + 'stories_for_kids' => 'Stories for Kids', + 'animation_and_manga' => 'Animation & Manga', + 'automotive' => 'Automotive', + 'aviation' => 'Aviation', + 'crafts' => 'Crafts', + 'games' => 'Games', + 'hobbies' => 'Hobbies', + 'home_and_garden' => 'Home & Garden', + 'video_games' => 'Video Games', + 'music_commentary' => 'Music Commentary', + 'music_history' => 'Music History', + 'music_interviews' => 'Music Interviews', + 'business_news' => 'Business News', + 'daily_news' => 'Daily News', + 'entertainment_news' => 'Entertainment News', + 'news_commentary' => 'News Commentary', + 'politics' => 'Politics', + 'sports_news' => 'Sports News', + 'tech_news' => 'Tech News', + 'buddhism' => 'Buddhism', + 'christianity' => 'Christianity', + 'hinduism' => 'Hinduism', + 'islam' => 'Islam', + 'judaism' => 'Judaism', + 'religion' => 'Religion', + 'spirituality' => 'Spirituality', + 'astronomy' => 'Astronomy', + 'chemistry' => 'Chemistry', + 'earth_sciences' => 'Earth Sciences', + 'life_sciences' => 'Life Sciences', + 'mathematics' => 'Mathematics', + 'natural_sciences' => 'Natural Sciences', + 'nature' => 'Nature', + 'physics' => 'Physics', + 'social_sciences' => 'Social Sciences', + 'documentary' => 'Documentary', + 'personal_journals' => 'Personal Journals', + 'philosophy' => 'Philosophy', + 'places_and_travel' => 'Places & Travel', + 'relationships' => 'Relationships', + 'baseball' => 'Baseball', + 'basketball' => 'Basketball', + 'cricket' => 'Cricket', + 'fantasy_sports' => 'Fantasy Sports', + 'football' => 'Football', + 'golf' => 'Golf', + 'hockey' => 'Hockey', + 'rugby' => 'Rugby', + 'running' => 'Running', + 'soccer' => 'Soccer', + 'swimming' => 'Swimming', + 'tennis' => 'Tennis', + 'volleyball' => 'Volleyball', + 'wilderness' => 'Wilderness', + 'wrestling' => 'Wrestling', + 'after_shows' => 'After Shows', + 'film_history' => 'Film History', + 'film_interviews' => 'Film Interviews', + 'film_reviews' => 'Film Reviews', + 'tv_reviews' => 'TV Reviews', + ], + 'publish_form' => [ + 'back_to_podcast_dashboard' => 'Back to podcast dashboard', + 'post' => 'Your announcement post', + 'post_hint' => + "Write a message to announce the publication of your podcast. The message will be featured in your podcast's homepage.", + 'message_placeholder' => 'Write your message…', + 'submit' => 'Publish', + 'publication_date' => 'Publication date', + 'publication_method' => [ + 'now' => 'Now', + 'schedule' => 'Schedule', + ], + 'scheduled_publication_date' => 'Scheduled publication date', + 'scheduled_publication_date_hint' => + 'You can schedule the podcast release by setting a future publication date. This field must be formatted as YYYY-MM-DD HH:mm', + 'submit_edit' => 'Edit publication', + 'cancel_publication' => 'Cancel publication', + 'message_warning' => 'You did not write a message for your announcement post!', + 'message_warning_hint' => 'Having a message increases social engagement, resulting in a better visibility for your podcast.', + 'message_warning_submit' => 'Publish anyway', + ], + 'publication_status_banner' => [ + 'draft_mode' => 'draft mode', + 'not_published' => 'This podcast is not yet published.', + 'scheduled' => 'This podcast is scheduled for publication on {publication_date}.', + ], + 'delete_form' => [ + 'disclaimer' => + "Deleting the podcast will delete all episodes, media files, posts and analytics associated with it. This action is irreversible, you will not be able to retrieve them afterwards.", + 'understand' => 'I understand, I want the podcast to be permanently deleted', + 'submit' => 'Delete', + ], + 'by' => 'By {publisher}', + 'season' => 'Season {seasonNumber}', + 'list_of_episodes_year' => '{year} episodes ({episodeCount})', + 'list_of_episodes_season' => + 'Season {seasonNumber} episodes ({episodeCount})', + 'no_episode' => 'No episode found!', + 'follow' => 'Follow', + 'followers' => '{numberOfFollowers, plural, + one {# follower} + other {# followers} + }', + 'posts' => '{numberOfPosts, plural, + one {# post} + other {# posts} + }', + 'activity' => 'Activity', + 'episodes' => 'Episodes', + 'sponsor' => 'Sponsor', + 'funding_links' => 'Funding links for {podcastTitle}', + 'find_on' => 'Find {podcastTitle} on', + 'listen_on' => 'Listen on', +]; diff --git a/modules/Admin/Language/zh-hant/PodcastNavigation.php b/modules/Admin/Language/zh-hant/PodcastNavigation.php new file mode 100644 index 00000000..bb777707 --- /dev/null +++ b/modules/Admin/Language/zh-hant/PodcastNavigation.php @@ -0,0 +1,42 @@ + 'Go to podcast page', + 'rss_feed' => 'RSS feed', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'podcast-persons-manage' => 'Manage persons', + 'podcast-imports' => 'Podcast imports', + 'podcast-imports-sync' => 'Sync feeds', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'podcast-analytics' => 'Audience overview', + 'podcast-analytics-webpages' => 'Web pages visits', + 'podcast-analytics-locations' => 'Locations', + 'podcast-analytics-unique-listeners' => 'Unique listeners', + 'podcast-analytics-players' => 'Players', + 'podcast-analytics-listening-time' => 'Listening time', + 'podcast-analytics-time-periods' => 'Time periods', + 'monetization' => 'Monetization', + 'subscription-list' => 'All subscriptions', + 'subscription-create' => 'Add subscription', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'broadcast' => 'Broadcast', + 'platforms-podcasting' => 'Podcasting apps', + 'platforms-social' => 'Social networks', + 'platforms-funding' => 'Funding links', + 'podcast-monetization-other' => 'Other', +]; diff --git a/modules/Admin/Language/zh-hant/Settings.php b/modules/Admin/Language/zh-hant/Settings.php new file mode 100644 index 00000000..4a70dcba --- /dev/null +++ b/modules/Admin/Language/zh-hant/Settings.php @@ -0,0 +1,58 @@ + 'General settings', + 'instance' => [ + 'title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared and at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + 'editSuccess' => 'Instance has been updated successfully!', + 'deleteIconSuccess' => 'Site icon has been remove successfully!', + ], + 'images' => [ + 'title' => 'Images', + 'subtitle' => 'Here you can regenerate all images based on the originals that were uploaded. To be used if you find that some images are missing. This task may take a while.', + 'regenerate' => 'Regenerate images', + 'regenerationSuccess' => 'All images have been regenerated successfully!', + ], + 'housekeeping' => [ + 'title' => 'Housekeeping', + 'subtitle' => 'Runs various housekeeping tasks. Use this feature if you ever encounter issues with media files or data integrity. These tasks may take a while.', + 'reset_counts' => 'Reset counts', + 'reset_counts_helper' => 'This option will recalculate and reset all data counts (number of followers, posts, comments, …).', + 'rewrite_media' => 'Rewrite media metadata', + 'rewrite_media_helper' => 'This option will delete all superfluous media files and recreate them (images, audio files, transcripts, chapters, …)', + 'rename_episodes_files' => 'Rename episode audio files', + 'rename_episodes_files_hint' => 'This option will rename all episodes audio files to a random string of characters. Use this if one of your private episodes link was leaked as this will effectively hide it.', + 'clear_cache' => 'Clear all cache', + 'clear_cache_helper' => 'This option will flush redis cache or writable/cache files.', + 'run' => 'Run housekeeping', + 'runSuccess' => 'Housekeeping has been run successfully!', + ], + 'theme' => [ + 'title' => 'Theme', + 'accent_section_title' => 'Accent color', + 'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.', + 'pine' => 'Pine', + 'crimson' => 'Crimson', + 'amber' => 'Amber', + 'lake' => 'Lake', + 'jacaranda' => 'Jacaranda', + 'onyx' => 'Onyx', + 'submit' => 'Save', + 'setInstanceThemeSuccess' => 'Theme has been updated successfully!', + ], +]; diff --git a/modules/Admin/Language/zh-hant/Soundbite.php b/modules/Admin/Language/zh-hant/Soundbite.php new file mode 100644 index 00000000..a3f828fe --- /dev/null +++ b/modules/Admin/Language/zh-hant/Soundbite.php @@ -0,0 +1,31 @@ + [ + 'title' => 'Soundbites', + 'soundbite' => 'Soundbite', + ], + 'messages' => [ + 'createSuccess' => 'Soundbite has been successfully created!', + 'deleteSuccess' => 'Soundbite has been successfully removed!', + ], + 'form' => [ + 'title' => 'New soundbite', + 'soundbite_title' => 'Soundbite title', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'submit' => 'Create soundbite', + ], + 'play' => 'Play soundbite', + 'stop' => 'Stop soundbite', + 'create' => 'New soundbite', + 'delete' => 'Delete soundbite', +]; diff --git a/modules/Admin/Language/zh-hant/Validation.php b/modules/Admin/Language/zh-hant/Validation.php new file mode 100644 index 00000000..f76c3163 --- /dev/null +++ b/modules/Admin/Language/zh-hant/Validation.php @@ -0,0 +1,17 @@ + + '{field} is either not an image, or it is not wide or tall enough.', + 'is_image_ratio' => + '{field} is either not an image or not of the right ratio.', + 'is_json' => '{field} contains invalid JSON.', +]; diff --git a/modules/Admin/Language/zh-hant/VideoClip.php b/modules/Admin/Language/zh-hant/VideoClip.php new file mode 100644 index 00000000..638de697 --- /dev/null +++ b/modules/Admin/Language/zh-hant/VideoClip.php @@ -0,0 +1,72 @@ + [ + 'title' => 'Video clips', + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Clip is waiting to be processed.', + 'pending' => 'pending', + 'pending_hint' => 'Clip will be generated shortly.', + 'running' => 'running', + 'running_hint' => 'Clip is being generated.', + 'failed' => 'failed', + 'failed_hint' => 'Clip could not be generated: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Clip was generated successfully!', + ], + 'clip' => 'Clip', + 'duration' => 'Job duration', + ], + 'title' => 'Video clip: {videoClipLabel}', + 'download_clip' => 'Download clip', + 'create' => 'New video clip', + 'go_to_page' => 'Go to clip page', + 'retry' => 'Retry clip generation', + 'delete' => 'Delete clip', + 'logs' => 'Job logs', + 'messages' => [ + 'alreadyExistingError' => 'The video clip you are trying to create already exists!', + 'addToQueueSuccess' => 'Video clip has been added to queue, awaiting to be created!', + 'deleteSuccess' => 'Video clip has been successfully removed!', + ], + 'format' => [ + 'landscape' => 'Landscape', + 'portrait' => 'Portrait', + 'squared' => 'Squared', + ], + 'form' => [ + 'title' => 'New video clip', + 'params_section_title' => 'Video clip parameters', + 'clip_title' => 'Clip title', + 'format' => [ + 'label' => 'Choose a format', + 'landscape_hint' => 'With a 16:9 ratio, landscape videos are great for PeerTube, Youtube and Vimeo.', + 'portrait_hint' => 'With a 9:16 ratio, portrait videos are great for TikTok, Youtube shorts and Instagram stories.', + 'squared_hint' => 'With a 1:1 ratio, squared videos are great for Mastodon, Facebook, Twitter and LinkedIn.', + ], + 'theme' => 'Select a theme', + 'start_time' => 'Start at', + 'duration' => 'Duration', + 'trim_start' => 'Trim start', + 'trim_end' => 'Trim end', + 'submit' => 'Create video clip', + ], + 'requirements' => [ + 'title' => 'Missing requirements', + 'missing' => 'You have missing requirements. Make sure to add all the required items to be allowed creating a video for this episode!', + 'ffmpeg' => 'FFmpeg', + 'gd' => 'Graphics Draw (GD)', + 'freetype' => 'Freetype library for GD', + 'transcript' => 'Transcript file (.srt)', + ], +]; diff --git a/modules/Analytics/AnalyticsTrait.php b/modules/Analytics/AnalyticsTrait.php new file mode 100644 index 00000000..a345c597 --- /dev/null +++ b/modules/Analytics/AnalyticsTrait.php @@ -0,0 +1,51 @@ +loggedIn()) { + return; + } + + helper('analytics'); + + set_user_session_deny_list_ip(); + set_user_session_browser(); + set_user_session_referer(); + set_user_session_entry_page(); + + $session = service('session'); + + if (! $session->get('denyListIp')) { + $db = db_connect(); + + $referer = $session->get('referer'); + $domain = + parse_url((string) $referer, PHP_URL_HOST) ?? '- Direct -'; + parse_str((string) parse_url((string) $referer, PHP_URL_QUERY), $queries); + $keywords = $queries['q'] ?? null; + + $procedureName = $db->prefixTable('analytics_website'); + $db->query("call {$procedureName}(?,?,?,?,?,?)", [ + $podcastId, + $session->get('browser') ?? '', + $session->get('entryPage'), + $referer, + $domain, + $keywords, + ]); + } + } +} diff --git a/modules/Analytics/Config/Analytics.php b/modules/Analytics/Config/Analytics.php new file mode 100644 index 00000000..fb86c03b --- /dev/null +++ b/modules/Analytics/Config/Analytics.php @@ -0,0 +1,40 @@ + + */ + public array $routeFilters = [ + 'analytics-full-data' => 'permission:podcast$1.view', + 'analytics-data' => 'permission:podcast$1.view', + 'analytics-filtered-data' => 'permission:podcast$1.view', + ]; + + /** + * -------------------------------------------------------------------------- + * Secret Salt + * -------------------------------------------------------------------------- + * + * The secret salt is a string of random characters that is used when hashing data. + * Each Castopod instance has its own secret salt so keys will never be the same. + * + * Example: + * Z&|qECKBrwgaaD>~;U/tXG1U%tSe_oi5Tzy)h>}5NC2npSrjvM0w_Q>cs=0o=H]* + */ + public string $salt = ''; +} diff --git a/modules/Analytics/Config/Routes.php b/modules/Analytics/Config/Routes.php new file mode 100644 index 00000000..9097151c --- /dev/null +++ b/modules/Analytics/Config/Routes.php @@ -0,0 +1,66 @@ +addPlaceholder( + 'class', + '\bPodcastByCountry|\bPodcastByEpisode|\bPodcastByHour|\bPodcastByPlayer|\bPodcastByRegion|\bPodcastByService|\bPodcast|\bWebsiteByBrowser|\bWebsiteByEntryPage|\bWebsiteByReferer', +); +$routes->addPlaceholder( + 'filter', + '\bWeekly|\bYearly|\bByDay|\bByWeekday|\bByMonth|\bByAppWeekly|\bByAppYearly|\bByOsWeekly|\bByDeviceWeekly|\bBots|\bByServiceWeekly|\bBandwidthByDay|\bUniqueListenersByDay|\bUniqueListenersByMonth|\bTotalListeningTimeByDay|\bTotalListeningTimeByMonth|\bByDomainWeekly|\bByDomainYearly|\bTotalBandwidthByMonth|\bTotalStorageByMonth', +); + +$routes->group('', [ + 'namespace' => 'Modules\Analytics\Controllers', +], static function ($routes): void { + $routes->group(config('Analytics')->gateway . '/(:num)/(:class)', static function ($routes): void { + $routes->get('/', 'AnalyticsController::getData/$1/$2', [ + 'as' => 'analytics-full-data', + 'filter' => config('Analytics') + ->routeFilters[ + 'analytics-full-data' + ], + ]); + $routes->get('(:filter)', 'AnalyticsController::getData/$1/$2/$3', [ + 'as' => 'analytics-data', + 'filter' => config('Analytics') + ->routeFilters['analytics-data'], + ]); + $routes->get( + '(:filter)/(:num)', + 'AnalyticsController::getData/$1/$2/$3/$4', + [ + 'as' => 'analytics-filtered-data', + 'filter' => config('Analytics') + ->routeFilters[ + 'analytics-filtered-data' + ], + ], + ); + }); + $routes->get(config('Analytics')->gateway . '/(:class)/(:filter)', 'AnalyticsController::getData/$1/$2', [ + 'as' => 'analytics-data-instance', + ]); + + /** + * @deprecated Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3) + */ + $routes->head('audio/(:base64)/(:any)', 'EpisodeAnalyticsController::hit/$1/$2'); + $routes->get('audio/(:base64)/(:any)', 'EpisodeAnalyticsController::hit/$1/$2'); +}); + +// Show the Unknown UserAgents +$routes->get('.well-known/unknown-useragents', 'UnknownUserAgentsController'); +$routes->get('.well-known/unknown-useragents/(:num)', 'UnknownUserAgentsController::index/$1'); diff --git a/modules/Analytics/Controllers/AnalyticsController.php b/modules/Analytics/Controllers/AnalyticsController.php new file mode 100644 index 00000000..adf7e3e0 --- /dev/null +++ b/modules/Analytics/Controllers/AnalyticsController.php @@ -0,0 +1,64 @@ +analyticsModel = model('Analytics' . $params[0] . 'Model'); + $this->methodName = 'getData' . $params[1]; + return $this->{$method}(); + } + + // @phpstan-ignore-next-line + $this->analyticsModel = model('Analytics' . $params[1] . 'Model'); + $this->methodName = 'getData' . (count($params) >= 3 ? $params[2] : ''); + + return $this->{$method}( + (int) $params[0], + count($params) >= 4 ? (int) $params[3] : null, + ); + } + + public function getData(?int $podcastId = null, ?int $episodeId = null): ResponseInterface + { + $methodName = $this->methodName; + + if ($podcastId === null) { + return $this->respond($this->analyticsModel->{$methodName}()); + } + + if ($episodeId === null) { + return $this->respond($this->analyticsModel->{$methodName}($podcastId)); + } + + return $this->respond($this->analyticsModel->{$methodName}($podcastId, $episodeId)); + } +} diff --git a/modules/Analytics/Controllers/EpisodeAnalyticsController.php b/modules/Analytics/Controllers/EpisodeAnalyticsController.php new file mode 100644 index 00000000..dfaff0a9 --- /dev/null +++ b/modules/Analytics/Controllers/EpisodeAnalyticsController.php @@ -0,0 +1,46 @@ +getEpisodeById($episodeData['episodeId']); + + if (! $episode instanceof Episode) { + throw PageNotFoundException::forPageNotFound(); + } + + return redirect()->route( + 'episode-audio', + [$episode->podcast->handle, $episode->slug, $episode->audio->file_extension], + ); + } +} diff --git a/app/Libraries/Analytics/Controllers/UnknownUserAgentsController.php b/modules/Analytics/Controllers/UnknownUserAgentsController.php similarity index 87% rename from app/Libraries/Analytics/Controllers/UnknownUserAgentsController.php rename to modules/Analytics/Controllers/UnknownUserAgentsController.php index 0747f6ed..2c4ad0bc 100644 --- a/app/Libraries/Analytics/Controllers/UnknownUserAgentsController.php +++ b/modules/Analytics/Controllers/UnknownUserAgentsController.php @@ -3,12 +3,12 @@ declare(strict_types=1); /** - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Controllers; +namespace Modules\Analytics\Controllers; use CodeIgniter\Controller; use CodeIgniter\HTTP\ResponseInterface; diff --git a/modules/Analytics/Database/Migrations/2017-12-01-000000_add_analytics_podcasts.php b/modules/Analytics/Database/Migrations/2017-12-01-000000_add_analytics_podcasts.php new file mode 100644 index 00000000..e95fb7a8 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-000000_add_analytics_podcasts.php @@ -0,0 +1,66 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'duration' => [ + // a hit in analytics podcast increments this value when a podcast is listened to in a given date. + // Here, the "cumulative listening time" on a podcast per day + // cannot surpass 999,999,999,999.999 seconds (~277,777,777 hours) - should be enough. + 'type' => 'DECIMAL(15,3)', + 'unsigned' => true, + ], + 'bandwidth' => [ + 'type' => 'BIGINT', + 'unsigned' => true, + ], + 'unique_listeners' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-010000_add_analytics_podcasts_by_episode.php b/modules/Analytics/Database/Migrations/2017-12-01-010000_add_analytics_podcasts_by_episode.php new file mode 100644 index 00000000..421d76ca --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-010000_add_analytics_podcasts_by_episode.php @@ -0,0 +1,59 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'episode_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'age' => [ + 'type' => 'INT', + 'comment' => 'Days since episode publication date', + 'unsigned' => true, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'episode_id']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_episode'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_episode'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-020000_add_analytics_podcasts_by_hour.php b/modules/Analytics/Database/Migrations/2017-12-01-020000_add_analytics_podcasts_by_hour.php new file mode 100644 index 00000000..3050d0af --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-020000_add_analytics_podcasts_by_hour.php @@ -0,0 +1,54 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'hour' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'hour']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_hour'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_hour'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-030000_add_analytics_podcasts_by_player.php b/modules/Analytics/Database/Migrations/2017-12-01-030000_add_analytics_podcasts_by_player.php new file mode 100644 index 00000000..e6b653c1 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-030000_add_analytics_podcasts_by_player.php @@ -0,0 +1,71 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'service' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + ], + 'app' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + ], + 'device' => [ + 'type' => 'VARCHAR', + 'constraint' => 32, + ], + 'os' => [ + 'type' => 'VARCHAR', + 'constraint' => 32, + ], + 'is_bot' => [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'service', 'app', 'device', 'os', 'is_bot']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_player'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_player'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-040000_add_analytics_podcasts_by_country.php b/modules/Analytics/Database/Migrations/2017-12-01-040000_add_analytics_podcasts_by_country.php new file mode 100644 index 00000000..cd668c0b --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-040000_add_analytics_podcasts_by_country.php @@ -0,0 +1,55 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'country_code' => [ + 'type' => 'VARCHAR', + 'constraint' => 3, + 'comment' => 'ISO 3166-1 code.', + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_country'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_country'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-050000_add_analytics_podcasts_by_region.php b/modules/Analytics/Database/Migrations/2017-12-01-050000_add_analytics_podcasts_by_region.php new file mode 100644 index 00000000..3e5ec698 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-050000_add_analytics_podcasts_by_region.php @@ -0,0 +1,68 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'country_code' => [ + 'type' => 'VARCHAR', + 'constraint' => 3, + 'comment' => 'ISO 3166-1 code.', + ], + 'region_code' => [ + 'type' => 'VARCHAR', + 'constraint' => 3, + 'comment' => 'ISO 3166-2 code.', + ], + 'latitude' => [ + 'type' => 'DECIMAL(8,6)', + 'null' => true, + ], + 'longitude' => [ + 'type' => 'DECIMAL(9,6)', + 'null' => true, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code', 'region_code']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_region'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_region'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-060000_add_analytics_website_by_browser.php b/modules/Analytics/Database/Migrations/2017-12-01-060000_add_analytics_website_by_browser.php new file mode 100644 index 00000000..8e37d154 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-060000_add_analytics_website_by_browser.php @@ -0,0 +1,55 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'browser' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + + $this->forge->addPrimaryKey(['podcast_id', 'date', 'browser']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_website_by_browser'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_website_by_browser'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-070000_add_analytics_website_by_referer.php b/modules/Analytics/Database/Migrations/2017-12-01-070000_add_analytics_website_by_referer.php new file mode 100644 index 00000000..cfbbd362 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-070000_add_analytics_website_by_referer.php @@ -0,0 +1,65 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'referer_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 512, + ], + 'domain' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + 'null' => true, + ], + 'keywords' => [ + 'type' => 'VARCHAR', + // length of referer_url (512) - domain (128) = 384 + 'constraint' => 384, + 'null' => true, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'referer_url']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_website_by_referer'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_website_by_referer'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-080000_add_analytics_website_by_entry_page.php b/modules/Analytics/Database/Migrations/2017-12-01-080000_add_analytics_website_by_entry_page.php new file mode 100644 index 00000000..bdfebcbc --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-080000_add_analytics_website_by_entry_page.php @@ -0,0 +1,54 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'entry_page_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 512, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'date', 'entry_page_url']); + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_website_by_entry_page'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_website_by_entry_page'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-090000_add_analytics_unknown_useragents.php b/modules/Analytics/Database/Migrations/2017-12-01-090000_add_analytics_unknown_useragents.php new file mode 100644 index 00000000..986848c5 --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-090000_add_analytics_unknown_useragents.php @@ -0,0 +1,55 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'useragent' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'unique' => true, + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + + $this->forge->addPrimaryKey('id'); + // `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Procedure will be used instead) + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_unknown_useragents'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_unknown_useragents'); + } +} diff --git a/modules/Analytics/Database/Migrations/2017-12-01-100000_add_analytics_podcasts_by_subscription.php b/modules/Analytics/Database/Migrations/2017-12-01-100000_add_analytics_podcasts_by_subscription.php new file mode 100644 index 00000000..44ea8c5e --- /dev/null +++ b/modules/Analytics/Database/Migrations/2017-12-01-100000_add_analytics_podcasts_by_subscription.php @@ -0,0 +1,58 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'episode_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'subscription_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'date' => [ + 'type' => 'DATE', + ], + 'hits' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 1, + ], + ]); + + $this->forge->addPrimaryKey(['podcast_id', 'episode_id', 'subscription_id', 'date']); + // `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Procedure will be used instead) + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addField( + '`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()', + ); + $this->forge->createTable('analytics_podcasts_by_subscription'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('analytics_podcasts_by_subscription'); + } +} diff --git a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php similarity index 80% rename from app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php rename to modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php index c6baebef..9472f0f2 100644 --- a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php +++ b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_podcasts_procedure.php @@ -5,17 +5,19 @@ declare(strict_types=1); /** * Class AddAnalyticsPodcastsProcedure Creates analytics_podcasts procedure in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Database\Migrations; +namespace Modules\Analytics\Database\Migrations; -use CodeIgniter\Database\Migration; +use App\Database\Migrations\BaseMigration; +use Override; -class AddAnalyticsPodcastsProcedure extends Migration +class AddAnalyticsPodcastsProcedure extends BaseMigration { + #[Override] public function up(): void { // Creates Procedure for data insertion @@ -38,20 +40,21 @@ class AddAnalyticsPodcastsProcedure extends Migration IN `p_filesize` INT UNSIGNED, IN `p_duration` DECIMAL(8,3) UNSIGNED, IN `p_age` INT UNSIGNED, - IN `p_new_listener` TINYINT(1) UNSIGNED + IN `p_new_listener` TINYINT(1) UNSIGNED, + IN `p_subscription_id` INT UNSIGNED ) MODIFIES SQL DATA DETERMINISTIC SQL SECURITY INVOKER COMMENT 'Add one hit in podcast logs tables.' BEGIN - SET @current_datetime = NOW(); + SET @current_datetime = UTC_TIMESTAMP(); SET @current_date = DATE(@current_datetime); SET @current_hour = HOUR(@current_datetime); IF NOT `p_bot` THEN - INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`) - VALUES (p_podcast_id, @current_date) + INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`, `duration`, `bandwidth`) + VALUES (p_podcast_id, @current_date, `p_duration`, `p_filesize`) ON DUPLICATE KEY UPDATE `duration`=`duration`+`p_duration`, `bandwidth`=`bandwidth`+`p_filesize`, @@ -69,6 +72,12 @@ class AddAnalyticsPodcastsProcedure extends Migration INSERT INTO `{$prefix}analytics_podcasts_by_region`(`podcast_id`, `country_code`, `region_code`, `latitude`, `longitude`, `date`) VALUES (p_podcast_id, p_country_code, p_region_code, p_latitude, p_longitude, @current_date) ON DUPLICATE KEY UPDATE `hits`=`hits`+1; + + IF `p_subscription_id` THEN + INSERT INTO `{$prefix}analytics_podcasts_by_subscription`(`podcast_id`, `episode_id`, `subscription_id`, `date`) + VALUES (p_podcast_id, p_episode_id, p_subscription_id, @current_date) + ON DUPLICATE KEY UPDATE `hits`=`hits`+1; + END IF; END IF; INSERT INTO `{$prefix}analytics_podcasts_by_player`(`podcast_id`, `service`, `app`, `device`, `os`, `is_bot`, `date`) VALUES (p_podcast_id, p_service, p_app, p_device, p_os, p_bot, @current_date) @@ -78,6 +87,7 @@ class AddAnalyticsPodcastsProcedure extends Migration $this->db->query($createQuery); } + #[Override] public function down(): void { $prefix = $this->db->getPrefix(); diff --git a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php similarity index 83% rename from app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php rename to modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php index e7a0f9b0..af627bf2 100644 --- a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php +++ b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_unknown_useragents_procedure.php @@ -5,17 +5,19 @@ declare(strict_types=1); /** * Class AddAnalyticsUnknownUseragentsProcedure Creates analytics_unknown_useragents procedure in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Database\Migrations; +namespace Modules\Analytics\Database\Migrations; -use CodeIgniter\Database\Migration; +use App\Database\Migrations\BaseMigration; +use Override; -class AddAnalyticsUnknownUseragentsProcedure extends Migration +class AddAnalyticsUnknownUseragentsProcedure extends BaseMigration { + #[Override] public function up(): void { // Creates Procedure for data insertion @@ -33,6 +35,7 @@ class AddAnalyticsUnknownUseragentsProcedure extends Migration $this->db->query($createQuery); } + #[Override] public function down(): void { $procedureName = $this->db->prefixTable('analytics_unknown_useragents'); diff --git a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php similarity index 87% rename from app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php rename to modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php index 8222abd9..dc2b0bd2 100644 --- a/app/Libraries/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php +++ b/modules/Analytics/Database/Migrations/2017-12-01-210000_add_analytics_website_procedure.php @@ -5,17 +5,19 @@ declare(strict_types=1); /** * Class AddAnalyticsWebsiteProcedure Creates analytics_website stored procedure in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Database\Migrations; +namespace Modules\Analytics\Database\Migrations; -use CodeIgniter\Database\Migration; +use App\Database\Migrations\BaseMigration; +use Override; -class AddAnalyticsWebsiteProcedure extends Migration +class AddAnalyticsWebsiteProcedure extends BaseMigration { + #[Override] public function up(): void { // Creates Procedure for data insertion @@ -35,7 +37,7 @@ class AddAnalyticsWebsiteProcedure extends Migration SQL SECURITY INVOKER BEGIN - SET @current_date = DATE(NOW()); + SET @current_date = DATE(UTC_TIMESTAMP()); INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`) VALUES (p_podcast_id, p_browser, @current_date) @@ -51,6 +53,7 @@ class AddAnalyticsWebsiteProcedure extends Migration $this->db->query($createQuery); } + #[Override] public function down(): void { $procedureName = $this->db->prefixTable('analytics_website'); diff --git a/modules/Analytics/Entities/AnalyticsPodcasts.php b/modules/Analytics/Entities/AnalyticsPodcasts.php new file mode 100644 index 00000000..45d4b624 --- /dev/null +++ b/modules/Analytics/Entities/AnalyticsPodcasts.php @@ -0,0 +1,45 @@ + + */ + protected $dates = ['date', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'podcast_id' => 'integer', + 'duration' => 'double', + 'bandwidth' => 'integer', + 'unique_listeners' => 'integer', + 'hits' => 'integer', + ]; +} diff --git a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByCountry.php b/modules/Analytics/Entities/AnalyticsPodcastsByCountry.php similarity index 81% rename from app/Libraries/Analytics/Entities/AnalyticsPodcastsByCountry.php rename to modules/Analytics/Entities/AnalyticsPodcastsByCountry.php index ca9ed80e..59ca02eb 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByCountry.php +++ b/modules/Analytics/Entities/AnalyticsPodcastsByCountry.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastsByCountry Entity for AnalyticsPodcastsByCountry * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -26,7 +27,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsPodcastsByCountry extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -34,9 +35,9 @@ class AnalyticsPodcastsByCountry extends Entity * @var array */ protected $casts = [ - 'podcast_id' => 'integer', + 'podcast_id' => 'integer', 'country_code' => 'string', - 'hits' => 'integer', + 'hits' => 'integer', ]; public function getLabels(): string diff --git a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByEpisode.php b/modules/Analytics/Entities/AnalyticsPodcastsByEpisode.php similarity index 82% rename from app/Libraries/Analytics/Entities/AnalyticsPodcastsByEpisode.php rename to modules/Analytics/Entities/AnalyticsPodcastsByEpisode.php index 07dd6967..1aa5959a 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByEpisode.php +++ b/modules/Analytics/Entities/AnalyticsPodcastsByEpisode.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastsByEpisode Entity for AnalyticsPodcastsByEpisode * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -25,7 +26,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsPodcastsByEpisode extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -35,6 +36,6 @@ class AnalyticsPodcastsByEpisode extends Entity protected $casts = [ 'podcast_id' => 'integer', 'episode_id' => 'integer', - 'hits' => 'integer', + 'hits' => 'integer', ]; } diff --git a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByHour.php b/modules/Analytics/Entities/AnalyticsPodcastsByHour.php similarity index 77% rename from app/Libraries/Analytics/Entities/AnalyticsPodcastsByHour.php rename to modules/Analytics/Entities/AnalyticsPodcastsByHour.php index 88856020..bfc33b04 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByHour.php +++ b/modules/Analytics/Entities/AnalyticsPodcastsByHour.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastsByHour Entity for AnalyticsPodcastsByHour * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -25,7 +26,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsPodcastsByHour extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -34,7 +35,7 @@ class AnalyticsPodcastsByHour extends Entity */ protected $casts = [ 'podcast_id' => 'integer', - 'hour' => 'integer', - 'hits' => 'integer', + 'hour' => 'integer', + 'hits' => 'integer', ]; } diff --git a/modules/Analytics/Entities/AnalyticsPodcastsByPlayer.php b/modules/Analytics/Entities/AnalyticsPodcastsByPlayer.php new file mode 100644 index 00000000..8fb0acf7 --- /dev/null +++ b/modules/Analytics/Entities/AnalyticsPodcastsByPlayer.php @@ -0,0 +1,47 @@ + + */ + protected $dates = ['date', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'podcast_id' => 'integer', + 'app' => '?string', + 'device' => '?string', + 'os' => '?string', + 'is_bot' => 'boolean', + 'hits' => 'integer', + ]; +} diff --git a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByRegion.php b/modules/Analytics/Entities/AnalyticsPodcastsByRegion.php similarity index 75% rename from app/Libraries/Analytics/Entities/AnalyticsPodcastsByRegion.php rename to modules/Analytics/Entities/AnalyticsPodcastsByRegion.php index f193f3cf..684667f3 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsPodcastsByRegion.php +++ b/modules/Analytics/Entities/AnalyticsPodcastsByRegion.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastsByRegion Entity for AnalyticsPodcastsByRegion * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -28,7 +29,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsPodcastsByRegion extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -36,12 +37,12 @@ class AnalyticsPodcastsByRegion extends Entity * @var array */ protected $casts = [ - 'podcast_id' => 'integer', + 'podcast_id' => 'integer', 'country_code' => 'string', - 'region_code' => '?string', - 'latitude' => '?double', - 'longitude' => '?double', - 'hits' => 'integer', + 'region_code' => '?string', + 'latitude' => '?double', + 'longitude' => '?double', + 'hits' => 'integer', ]; public function getCountryCode(): string diff --git a/modules/Analytics/Entities/AnalyticsPodcastsByService.php b/modules/Analytics/Entities/AnalyticsPodcastsByService.php new file mode 100644 index 00000000..fb8a0366 --- /dev/null +++ b/modules/Analytics/Entities/AnalyticsPodcastsByService.php @@ -0,0 +1,55 @@ + + */ + protected $dates = ['date', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'podcast_id' => 'integer', + 'app' => '?string', + 'device' => '?string', + 'os' => '?string', + 'is_bot' => 'boolean', + 'hits' => 'integer', + ]; + + public function getLabels(): string + { + return UserAgentsRSS::getName($this->attributes['labels']) ?? + $this->attributes['labels']; + } +} diff --git a/modules/Analytics/Entities/AnalyticsPodcastsBySubscription.php b/modules/Analytics/Entities/AnalyticsPodcastsBySubscription.php new file mode 100644 index 00000000..09974b76 --- /dev/null +++ b/modules/Analytics/Entities/AnalyticsPodcastsBySubscription.php @@ -0,0 +1,41 @@ + + */ + protected $dates = ['date', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'podcast_id' => 'integer', + 'episode_id' => 'integer', + 'subscription_id' => 'integer', + 'hits' => 'integer', + ]; +} diff --git a/app/Libraries/Analytics/Entities/AnalyticsUnknownUserAgent.php b/modules/Analytics/Entities/AnalyticsUnknownUserAgent.php similarity index 77% rename from app/Libraries/Analytics/Entities/AnalyticsUnknownUserAgent.php rename to modules/Analytics/Entities/AnalyticsUnknownUserAgent.php index b5d460e8..016a3d0a 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsUnknownUserAgent.php +++ b/modules/Analytics/Entities/AnalyticsUnknownUserAgent.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsUnknownUseragents Entity for AnalyticsUnknownUseragents * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $id @@ -24,7 +25,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsUnknownUserAgent extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['created_at', 'updated_at']; @@ -32,8 +33,8 @@ class AnalyticsUnknownUserAgent extends Entity * @var array */ protected $casts = [ - 'id' => 'integer', + 'id' => 'integer', 'useragent' => 'integer', - 'hits' => 'integer', + 'hits' => 'integer', ]; } diff --git a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByBrowser.php b/modules/Analytics/Entities/AnalyticsWebsiteByBrowser.php similarity index 78% rename from app/Libraries/Analytics/Entities/AnalyticsWebsiteByBrowser.php rename to modules/Analytics/Entities/AnalyticsWebsiteByBrowser.php index 0dcb8e34..9d764f7e 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByBrowser.php +++ b/modules/Analytics/Entities/AnalyticsWebsiteByBrowser.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsWebsiteByBrowser Entity for AnalyticsWebsiteByBrowser * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -25,7 +26,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsWebsiteByBrowser extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -34,7 +35,7 @@ class AnalyticsWebsiteByBrowser extends Entity */ protected $casts = [ 'podcast_id' => 'integer', - 'browser' => 'string', - 'hits' => 'integer', + 'browser' => 'string', + 'hits' => 'integer', ]; } diff --git a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByEntryPage.php b/modules/Analytics/Entities/AnalyticsWebsiteByEntryPage.php similarity index 77% rename from app/Libraries/Analytics/Entities/AnalyticsWebsiteByEntryPage.php rename to modules/Analytics/Entities/AnalyticsWebsiteByEntryPage.php index 4e59db25..7e8294c2 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByEntryPage.php +++ b/modules/Analytics/Entities/AnalyticsWebsiteByEntryPage.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsWebsiteByEntryPage Entity for AnalyticsWebsiteByEntryPage * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -25,7 +26,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsWebsiteByEntryPage extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -33,8 +34,8 @@ class AnalyticsWebsiteByEntryPage extends Entity * @var array */ protected $casts = [ - 'podcast_id' => 'integer', + 'podcast_id' => 'integer', 'entry_page_url' => 'string', - 'hits' => 'integer', + 'hits' => 'integer', ]; } diff --git a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByReferer.php b/modules/Analytics/Entities/AnalyticsWebsiteByReferer.php similarity index 78% rename from app/Libraries/Analytics/Entities/AnalyticsWebsiteByReferer.php rename to modules/Analytics/Entities/AnalyticsWebsiteByReferer.php index 570fad0d..c0edf9c8 100644 --- a/app/Libraries/Analytics/Entities/AnalyticsWebsiteByReferer.php +++ b/modules/Analytics/Entities/AnalyticsWebsiteByReferer.php @@ -5,14 +5,15 @@ declare(strict_types=1); /** * Class class AnalyticsWebsiteByReferer Entity for AnalyticsWebsiteByReferer * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Entities; +namespace Modules\Analytics\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * @property int $podcast_id @@ -25,7 +26,7 @@ use CodeIgniter\Entity\Entity; class AnalyticsWebsiteByReferer extends Entity { /** - * @var string[] + * @var list */ protected $dates = ['date', 'created_at', 'updated_at']; @@ -33,8 +34,8 @@ class AnalyticsWebsiteByReferer extends Entity * @var array */ protected $casts = [ - 'podcast_id' => 'integer', + 'podcast_id' => 'integer', 'referer_url' => 'string', - 'hits' => 'integer', + 'hits' => 'integer', ]; } diff --git a/modules/Analytics/Helpers/analytics_helper.php b/modules/Analytics/Helpers/analytics_helper.php new file mode 100644 index 00000000..adf97da4 --- /dev/null +++ b/modules/Analytics/Helpers/analytics_helper.php @@ -0,0 +1,360 @@ +server('HTTP_X_FORWARDED_FOR'))) { + return $superglobals->server('HTTP_X_FORWARDED_FOR'); + } + + return $superglobals->server('REMOTE_ADDR'); + } +} + +if (! function_exists('set_user_session_deny_list_ip')) { + /** + * Set user country in session variable, for analytic purposes + */ + function set_user_session_deny_list_ip(): void + { + $session = service('session'); + + if (! $session->has('denyListIp')) { + $session->set('denyListIp', IpDb::find(client_ip()) !== null); + } + } +} + +if (! function_exists('set_user_session_location')) { + /** + * Set user country in session variable, for analytic purposes + */ + function set_user_session_location(): void + { + $session = service('session'); + + $location = [ + 'countryCode' => 'N/A', + 'regionCode' => 'N/A', + 'latitude' => null, + 'longitude' => null, + ]; + + // Finds location: + if (! $session->has('location')) { + try { + $cityReader = new Reader(WRITEPATH . 'uploads/GeoLite2-City/GeoLite2-City.mmdb'); + $city = $cityReader->city(client_ip()); + + $location = [ + 'countryCode' => $city->country->isoCode ?? 'N/A', + 'regionCode' => $city->subdivisions[0]->isoCode ?? 'N/A', + 'latitude' => round($city->location->latitude, 3), + 'longitude' => round($city->location->longitude, 3), + ]; + // If things go wrong the show must go on and the user must be able to download the file + } catch (Exception) { + } + + $session->set('location', $location); + } + } +} + +if (! function_exists('set_user_session_player')) { + /** + * Set user player in session variable, for analytic purposes + */ + function set_user_session_player(): void + { + $session = service('session'); + + if (! $session->has('player')) { + $playerFound = null; + $userAgent = service('superglobals') + ->server('HTTP_USER_AGENT'); + + try { + $playerFound = UserAgents::find($userAgent); + // If things go wrong the show must go on and the user must be able to download the file + } catch (Exception) { + } + + if ($playerFound) { + $session->set('player', $playerFound); + } else { + $session->set('player', [ + 'app' => '- unknown -', + 'device' => '', + 'os' => '', + 'bot' => 0, + ]); + // Add to unknown list + try { + $db = db_connect(); + $procedureNameAnalyticsUnknownUseragents = $db->prefixTable('analytics_unknown_useragents'); + $db->query("CALL {$procedureNameAnalyticsUnknownUseragents}(?)", [$userAgent]); + // If things go wrong the show must go on and the user must be able to download the file + } catch (Exception) { + } + } + } + } +} + +if (! function_exists('set_user_session_browser')) { + /** + * Set user browser in session variable, for analytic purposes + * + * FIXME: session key should be null instead of "Could not get browser name" + */ + function set_user_session_browser(): void + { + $session = service('session'); + + if (! $session->has('browser')) { + $browserName = '- Other -'; + try { + $whichbrowser = new Parser(getallheaders()); + $browserName = $whichbrowser->browser->name; + } catch (Exception) { + $browserName = '- Could not get browser name -'; + } + + if ($browserName === '') { + $browserName = '- Could not get browser name -'; + } + + $session->set('browser', $browserName); + } + } +} + +if (! function_exists('set_user_session_referer')) { + /** + * Set user referer in session variable, for analytic purposes + */ + function set_user_session_referer(): void + { + $session = service('session'); + + $newreferer = service('superglobals') + ->server('HTTP_REFERER') ?? '- Direct -'; + $newreferer = + parse_url((string) $newreferer, PHP_URL_HOST) === + parse_url(current_url(false), PHP_URL_HOST) + ? '- Direct -' + : $newreferer; + if (! $session->has('referer') || $newreferer !== '- Direct -') { + $session->set('referer', $newreferer); + } + } +} + +if (! function_exists('set_user_session_entry_page')) { + /** + * Set user entry page in session variable, for analytic purposes + */ + function set_user_session_entry_page(): void + { + $session = service('session'); + + $entryPage = service('superglobals') + ->server('REQUEST_URI'); + if (! $session->has('entryPage')) { + $session->set('entryPage', $entryPage); + } + } +} + +if (! function_exists('podcast_hit')) { + /** + * Counting podcast episode downloads for analytic purposes ✅ No IP address is ever stored on the server. ✅ Only + * aggregate data is stored in the database. We follow IAB Podcast Measurement Technical Guidelines Version 2.0: + * https://iabtechlab.com/standards/podcast-measurement-guidelines/ + * https://iabtechlab.com/wp-content/uploads/2017/12/Podcast_Measurement_v2-Dec-20-2017.pdf + * ✅ 24-hour window + * ✅ Castopod does not do pre-load + * ✅ IP deny list https://github.com/client9/ipcat + * ✅ User-agent Filtering https://github.com/opawg/user-agents-v2 + * ✅ RSS User-agent https://github.com/opawg/podcast-rss-useragents + * ✅ Ignores 2 bytes range "Range: 0-1" (performed by official Apple iOS Podcast app) + * ✅ In case of partial content, adds up all requests to check >1mn was downloaded + * ✅ Identifying Uniques is done with a combination of IP Address and User Agent + * + * @param integer $podcastId The podcast ID + * @param integer $episodeId The Episode ID + * @param integer $bytesThreshold The minimum total number of bytes that must be downloaded so that an episode is counted (>1mn) + * @param integer $fileSize The podcast complete file size + * @param double $duration The episode duration in seconds + * @param int $publicationTime The episode's publication time as a UNIX timestamp + * @param string $serviceName The name of the service that had fetched the RSS feed + */ + function podcast_hit( + int $podcastId, + int $episodeId, + int $bytesThreshold, + int $fileSize, + float $duration, + int $publicationTime, + string $serviceName, + ?int $subscriptionId, + ): void { + $session = service('session'); + + $clientIp = client_ip(); + + // We try to count (but if things went wrong the show should go on and the user should be able to download the file): + try { + // If the user IP is denied it's probably a bot: + if ($session->get('denyListIp')) { + $session->get('player')['bot'] = true; + } + + $superglobals = service('superglobals'); + //We get the HTTP header field `Range`: + $httpRange = $superglobals->server('HTTP_RANGE') ?? null; + + $salt = config('Analytics') + ->salt; + // We create a sha1 hash for this Salt+Current_Date+IP_Address+User_Agent+Episode_ID (used to count only once multiple episode downloads): + $episodeListenerHashId = + 'Analytics_Episode_' . + sha1( + $salt . '_' . date( + 'Y-m-d', + ) . '_' . $clientIp . '_' . $superglobals->server('HTTP_USER_AGENT') . '_' . $episodeId, + ); + // The cache expires at midnight: + $secondsToMidnight = strtotime('tomorrow') - time(); + + /** @var int|null $downloadedBytes */ + $downloadedBytes = cache($episodeListenerHashId); + + if ($downloadedBytes === null) { + // If it was never downloaded that means that zero bytes were downloaded: + $downloadedBytes = 0; + } + + // If the number of downloaded bytes was previously below the 1mn threshold we go on: + // (Otherwise it means that this was already counted, therefore we don't do anything) + if ($downloadedBytes < $bytesThreshold) { + // If HTTP_RANGE is null we are downloading the complete file: + if (! $httpRange) { + $downloadedBytes = $fileSize; + } elseif ($httpRange !== 'bytes=0-1') { + // [0-1] bytes range requests are used (by Apple) to check that file exists and that 206 partial content is working. + // We don't count these requests. + // We calculate how many bytes are being downloaded based on HTTP_RANGE values: + $ranges = explode(',', substr((string) $httpRange, 6)); + foreach ($ranges as $range) { + $parts = explode('-', $range); + $downloadedBytes += array_key_exists(1, $parts) + ? $fileSize + : (int) $parts[1] - (int) $parts[0]; + } + } + + // We save the number of downloaded bytes for this user and this episode: + cache() + ->save($episodeListenerHashId, $downloadedBytes, $secondsToMidnight); + + // If more that 1mn was downloaded, that's a hit, we send that to the database: + if ($downloadedBytes >= $bytesThreshold) { + $db = db_connect(); + $procedureName = $db->prefixTable('analytics_podcasts'); + + $age = intdiv(time() - $publicationTime, 86400); + + // We create a sha1 hash for this Salt+Current_Date+IP_Address+User_Agent+Podcast_ID (used to count unique listeners): + $podcastListenerHashId = + 'Analytics_Podcast_' . + sha1( + $salt . '_' . date( + 'Y-m-d', + ) . '_' . $clientIp . '_' . $superglobals->server('HTTP_USER_AGENT') . '_' . $podcastId, + ); + $newListener = 1; + + // Has this listener already downloaded an episode today: + /** @var int|null $downloadsByUser */ + $downloadsByUser = cache($podcastListenerHashId); + + // We add one download + if ($downloadsByUser === null) { + $newListener = 0; + ++$downloadsByUser; + } else { + $downloadsByUser = 1; + } + + // We save the download count for this user until midnight: + cache() + ->save($podcastListenerHashId, $downloadsByUser, $secondsToMidnight); + + $db->query( + "CALL {$procedureName}(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", + [ + $podcastId, + $episodeId, + $session->get('location')['countryCode'], + $session->get('location')['regionCode'], + $session->get('location')['latitude'], + $session->get('location')['longitude'], + $serviceName, + $session->get('player')['app'], + $session->get('player')['device'], + $session->get('player')['os'], + $session->get('player')['bot'], + $fileSize, + $duration, + $age, + $newListener, + $subscriptionId, + ], + ); + } + } + } catch (Exception $exception) { + // If things go wrong the show must go on and the user must be able to download the file + log_message('critical', $exception->getMessage()); + } + } +} diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByCountryModel.php b/modules/Analytics/Models/AnalyticsPodcastByCountryModel.php similarity index 89% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByCountryModel.php rename to modules/Analytics/Models/AnalyticsPodcastByCountryModel.php index c15b671f..b79d6de8 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByCountryModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByCountryModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByCountryModel Model for analytics_podcasts_by_country table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByCountry; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByCountry; class AnalyticsPodcastByCountryModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByCountryModel extends Model protected $table = 'analytics_podcasts_by_country'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByCountry::class; @@ -52,7 +52,7 @@ class AnalyticsPodcastByCountryModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneWeekAgo, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -80,7 +80,7 @@ class AnalyticsPodcastByCountryModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneYearAgo, + 'date >' => $oneYearAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -89,6 +89,7 @@ class AnalyticsPodcastByCountryModel extends Model cache() ->save("{$podcastId}_analytics_podcast_by_country_yearly", $found, 600); } + return $found; } } diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByEpisodeModel.php b/modules/Analytics/Models/AnalyticsPodcastByEpisodeModel.php similarity index 87% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByEpisodeModel.php rename to modules/Analytics/Models/AnalyticsPodcastByEpisodeModel.php index a1a63388..cb4d47a9 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByEpisodeModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByEpisodeModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByEpisodeModel Model for analytics_podcasts_by_episodes table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByEpisode; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByEpisode; class AnalyticsPodcastByEpisodeModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByEpisodeModel extends Model protected $table = 'analytics_podcasts_by_episode'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByEpisode::class; @@ -50,7 +50,7 @@ class AnalyticsPodcastByEpisodeModel extends Model ->where([ 'episode_id' => $episodeId, 'podcast_id' => $podcastId, - 'age <' => 60, + 'age <' => 60, ]) ->groupBy('labels') ->orderBy('labels', 'ASC') @@ -66,7 +66,7 @@ class AnalyticsPodcastByEpisodeModel extends Model /** * @return AnalyticsPodcastsByEpisode[] */ - public function getDataByMonth(int $podcastId, int $episodeId = null): array + public function getDataByMonth(int $podcastId, ?int $episodeId = null): array { if ( ! ($found = cache("{$podcastId}_{$episodeId}_analytics_podcast_by_episode_by_month")) diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByHourModel.php b/modules/Analytics/Models/AnalyticsPodcastByHourModel.php similarity index 84% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByHourModel.php rename to modules/Analytics/Models/AnalyticsPodcastByHourModel.php index d582f77a..071df0f9 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByHourModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByHourModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByHour Model for analytics_podcasts_by_hour table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByHour; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByHour; class AnalyticsPodcastByHourModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByHourModel extends Model protected $table = 'analytics_podcasts_by_hour'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByHour::class; @@ -49,7 +49,7 @@ class AnalyticsPodcastByHourModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->groupBy('labels') ->orderBy('labels', 'ASC') diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByPlayerModel.php b/modules/Analytics/Models/AnalyticsPodcastByPlayerModel.php similarity index 85% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByPlayerModel.php rename to modules/Analytics/Models/AnalyticsPodcastByPlayerModel.php index 76da85df..1cc7d74d 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByPlayerModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByPlayerModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByPlayerModel Model for analytics_podcasts_by_player table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByPlayer; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByPlayer; class AnalyticsPodcastByPlayerModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByPlayerModel extends Model protected $table = 'analytics_podcasts_by_player'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByPlayer::class; @@ -52,9 +52,9 @@ class AnalyticsPodcastByPlayerModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'app !=' => '', - 'is_bot' => 0, - 'date >' => $oneWeekAgo, + 'app !=' => '', + 'is_bot' => 0, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -62,6 +62,7 @@ class AnalyticsPodcastByPlayerModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_player_by_app_weekly", $found, 600); } + return $found; } @@ -80,9 +81,9 @@ class AnalyticsPodcastByPlayerModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'app !=' => '', - 'is_bot' => 0, - 'date >' => $oneYearAgo, + 'app !=' => '', + 'is_bot' => 0, + 'date >' => $oneYearAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -90,6 +91,7 @@ class AnalyticsPodcastByPlayerModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_player_by_app_yearly", $found, 600); } + return $found; } @@ -108,10 +110,10 @@ class AnalyticsPodcastByPlayerModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'app !=' => '', - 'os !=' => '', - 'is_bot' => 0, - 'date >' => $oneWeekAgo, + 'app !=' => '', + 'os !=' => '', + 'is_bot' => 0, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -119,6 +121,7 @@ class AnalyticsPodcastByPlayerModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_player_by_os_weekly", $found, 600); } + return $found; } @@ -137,9 +140,9 @@ class AnalyticsPodcastByPlayerModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'device !=' => '', - 'is_bot' => 0, - 'date >' => $oneWeekAgo, + 'device !=' => '', + 'is_bot' => 0, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -147,6 +150,7 @@ class AnalyticsPodcastByPlayerModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_player_by_device_weekly", $found, 600); } + return $found; } @@ -165,8 +169,8 @@ class AnalyticsPodcastByPlayerModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'is_bot' => 1, - 'date >' => $oneYearAgo, + 'is_bot' => 1, + 'date >' => $oneYearAgo, ]) ->groupBy('labels') ->orderBy('labels', 'ASC') @@ -175,6 +179,7 @@ class AnalyticsPodcastByPlayerModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_player_bots", $found, 600); } + return $found; } } diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByRegionModel.php b/modules/Analytics/Models/AnalyticsPodcastByRegionModel.php similarity index 86% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByRegionModel.php rename to modules/Analytics/Models/AnalyticsPodcastByRegionModel.php index 22d59d6f..0bba643b 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByRegionModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByRegionModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByRegionModel Model for analytics_podcasts_by_region table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByRegion; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByRegion; class AnalyticsPodcastByRegionModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByRegionModel extends Model protected $table = 'analytics_podcasts_by_region'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByRegion::class; @@ -56,7 +56,7 @@ class AnalyticsPodcastByRegionModel extends Model ->groupBy('country_code, region_code') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-1 week')), + 'date >' => date('Y-m-d', strtotime('-1 week')), ]) ->orderBy('value', 'DESC') ->findAll(); @@ -64,6 +64,7 @@ class AnalyticsPodcastByRegionModel extends Model cache() ->save("{$podcastId}_analytics_podcast_by_region_{$locale}", $found, 600); } + return $found; } } diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastByServiceModel.php b/modules/Analytics/Models/AnalyticsPodcastByServiceModel.php similarity index 84% rename from app/Libraries/Analytics/Models/AnalyticsPodcastByServiceModel.php rename to modules/Analytics/Models/AnalyticsPodcastByServiceModel.php index 160c8327..e7bacc11 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastByServiceModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastByServiceModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsPodcastByServiceModel Model for analytics_podcasts_by_player table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcastsByService; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcastsByService; class AnalyticsPodcastByServiceModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsPodcastByServiceModel extends Model protected $table = 'analytics_podcasts_by_player'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcastsByService::class; @@ -53,8 +53,8 @@ class AnalyticsPodcastByServiceModel extends Model ->where([ 'podcast_id' => $podcastId, 'service !=' => '', - 'is_bot' => 0, - 'date >' => $oneWeekAgo, + 'is_bot' => 0, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -62,6 +62,7 @@ class AnalyticsPodcastByServiceModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_service_weekly", $found, 600); } + return $found; } } diff --git a/modules/Analytics/Models/AnalyticsPodcastBySubscriptionModel.php b/modules/Analytics/Models/AnalyticsPodcastBySubscriptionModel.php new file mode 100644 index 00000000..c629d057 --- /dev/null +++ b/modules/Analytics/Models/AnalyticsPodcastBySubscriptionModel.php @@ -0,0 +1,61 @@ + + */ + protected $returnType = AnalyticsPodcastsBySubscription::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = false; + + public function getNumberOfDownloadsLast3Months(int $podcastId, int $subscriptionId): int + { + $cacheName = "{$podcastId}_{$subscriptionId}_analytics_podcast_by_subscription"; + + if ( + ! ($found = cache($cacheName)) + ) { + $found = (int) ($this->builder() + ->selectSum('hits', 'total_hits') + ->where([ + 'podcast_id' => $podcastId, + 'subscription_id' => $subscriptionId, + ]) + ->where('`date` >= UTC_TIMESTAMP() - INTERVAL 3 month', null, false) + ->get() + ->getResultArray())[0]['total_hits']; + + cache() + ->save($cacheName, $found, 600); + } + + return $found; + } +} diff --git a/app/Libraries/Analytics/Models/AnalyticsPodcastModel.php b/modules/Analytics/Models/AnalyticsPodcastModel.php similarity index 76% rename from app/Libraries/Analytics/Models/AnalyticsPodcastModel.php rename to modules/Analytics/Models/AnalyticsPodcastModel.php index f2f2a702..751620e2 100644 --- a/app/Libraries/Analytics/Models/AnalyticsPodcastModel.php +++ b/modules/Analytics/Models/AnalyticsPodcastModel.php @@ -5,15 +5,16 @@ declare(strict_types=1); /** * Class AnalyticsPodcastModel Model for analytics_podcasts table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsPodcasts; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsPodcasts; +use Modules\Media\Models\MediaModel; class AnalyticsPodcastModel extends Model { @@ -23,7 +24,7 @@ class AnalyticsPodcastModel extends Model protected $table = 'analytics_podcasts'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsPodcasts::class; @@ -48,7 +49,7 @@ class AnalyticsPodcastModel extends Model $found = $this->select('date as labels, hits as values') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->orderBy('labels', 'ASC') ->findAll(); @@ -56,6 +57,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_by_day", $found, 600); } + return $found; } @@ -71,7 +73,7 @@ class AnalyticsPodcastModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->groupBy('labels, sort_labels') ->orderBy('sort_labels', 'ASC') @@ -80,6 +82,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcasts_by_weekday", $found, 600); } + return $found; } @@ -91,10 +94,10 @@ class AnalyticsPodcastModel extends Model public function getDataBandwidthByDay(int $podcastId): array { if (! ($found = cache("{$podcastId}_analytics_podcast_by_bandwidth"))) { - $found = $this->select('date as labels, round(bandwidth / 1048576, 1) as `values`') + $found = $this->select('date as labels, ROUND(bandwidth / 1000000, 2) as `values`') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->orderBy('labels', 'ASC') ->findAll(); @@ -102,6 +105,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_by_bandwidth", $found, 600); } + return $found; } @@ -125,6 +129,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_by_month", $found, 600); } + return $found; } @@ -141,7 +146,7 @@ class AnalyticsPodcastModel extends Model $found = $this->select('date as labels, unique_listeners as values') ->where([ 'podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->orderBy('labels', 'ASC') ->findAll(); @@ -149,6 +154,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_unique_listeners_by_day", $found, 600); } + return $found; } @@ -174,6 +180,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_unique_listeners_by_month", $found, 600); } + return $found; } @@ -191,7 +198,7 @@ class AnalyticsPodcastModel extends Model ->selectSum('duration', 'values') ->where([ $this->table . '.podcast_id' => $podcastId, - 'date >' => date('Y-m-d', strtotime('-60 days')), + 'date >' => date('Y-m-d', strtotime('-60 days')), ]) ->groupBy('labels') ->orderBy('labels', 'ASC') @@ -200,6 +207,7 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_listening_time_by_day", $found, 600); } + return $found; } @@ -225,6 +233,50 @@ class AnalyticsPodcastModel extends Model cache() ->save("{$podcastId}_analytics_podcast_listening_time_by_month", $found, 600); } + + return $found; + } + + /** + * Gets total bandwidth data for instance + * + * @return AnalyticsPodcasts[] + */ + public function getDataTotalBandwidthByMonth(): array + { + if (! ($found = cache('analytics_total_bandwidth_by_month'))) { + $found = $this->select( + 'DATE_FORMAT(updated_at,"%Y-%m") as labels, ROUND(sum(bandwidth) / 1000000, 2) as `values`', + ) + ->groupBy('labels') + ->orderBy('labels', 'ASC') + ->findAll(); + + cache() + ->save('analytics_total_bandwidth_by_month', $found, 600); + } + + return $found; + } + + /** + * Get total storage + * + * @return AnalyticsPodcasts[] + */ + public function getDataTotalStorageByMonth(): array + { + if (! ($found = cache('analytics_total_storage_by_month'))) { + $found = new MediaModel() + ->select('DATE_FORMAT(uploaded_at,"%Y-%m") as labels, ROUND(sum(file_size) / 1000000, 2) as `values`') + ->groupBy('labels') + ->orderBy('labels', 'ASC') + ->findAll(); + + cache() + ->save('analytics_total_storage_by_month', $found, 600); + } + return $found; } } diff --git a/modules/Analytics/Models/AnalyticsUnknownUserAgentsModel.php b/modules/Analytics/Models/AnalyticsUnknownUserAgentsModel.php new file mode 100644 index 00000000..59053466 --- /dev/null +++ b/modules/Analytics/Models/AnalyticsUnknownUserAgentsModel.php @@ -0,0 +1,48 @@ + + */ + protected $returnType = AnalyticsUnknownUserAgent::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = false; + + /** + * @return mixed[] + */ + public function getUserAgents(int $lastKnownId = 0): array + { + return $this->where('id >', $lastKnownId) + ->findAll(); + } +} diff --git a/app/Libraries/Analytics/Models/AnalyticsWebsiteByBrowserModel.php b/modules/Analytics/Models/AnalyticsWebsiteByBrowserModel.php similarity index 86% rename from app/Libraries/Analytics/Models/AnalyticsWebsiteByBrowserModel.php rename to modules/Analytics/Models/AnalyticsWebsiteByBrowserModel.php index 438beda4..e5398311 100644 --- a/app/Libraries/Analytics/Models/AnalyticsWebsiteByBrowserModel.php +++ b/modules/Analytics/Models/AnalyticsWebsiteByBrowserModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsWebsiteByBrowserModel Model for analytics_website_by_browser table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsWebsiteByBrowser; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsWebsiteByBrowser; class AnalyticsWebsiteByBrowserModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsWebsiteByBrowserModel extends Model protected $table = 'analytics_website_by_browser'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsWebsiteByBrowser::class; @@ -50,7 +50,7 @@ class AnalyticsWebsiteByBrowserModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneWeekAgo, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -59,6 +59,7 @@ class AnalyticsWebsiteByBrowserModel extends Model cache() ->save("{$podcastId}_analytics_website_by_browser", $found, 600); } + return $found; } } diff --git a/app/Libraries/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php b/modules/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php similarity index 86% rename from app/Libraries/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php rename to modules/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php index b49bb1a6..90bfcfde 100644 --- a/app/Libraries/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php +++ b/modules/Analytics/Models/AnalyticsWebsiteByEntryPageModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsWebsiteByEntryPageModel Model for analytics_website_by_entry_page table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsWebsiteByEntryPage; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsWebsiteByEntryPage; class AnalyticsWebsiteByEntryPageModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsWebsiteByEntryPageModel extends Model protected $table = 'analytics_website_by_entry_page'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsWebsiteByEntryPage::class; @@ -50,7 +50,7 @@ class AnalyticsWebsiteByEntryPageModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneWeekAgo, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -58,6 +58,7 @@ class AnalyticsWebsiteByEntryPageModel extends Model cache() ->save("{$podcastId}_analytics_website_by_entry_page", $found, 600); } + return $found; } } diff --git a/app/Libraries/Analytics/Models/AnalyticsWebsiteByRefererModel.php b/modules/Analytics/Models/AnalyticsWebsiteByRefererModel.php similarity index 86% rename from app/Libraries/Analytics/Models/AnalyticsWebsiteByRefererModel.php rename to modules/Analytics/Models/AnalyticsWebsiteByRefererModel.php index fd4ff818..cd8fb2a5 100644 --- a/app/Libraries/Analytics/Models/AnalyticsWebsiteByRefererModel.php +++ b/modules/Analytics/Models/AnalyticsWebsiteByRefererModel.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * Class AnalyticsWebsiteByRefererModel Model for analytics_website_by_referer table in database * - * @copyright 2020 Podlibre + * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace Analytics\Models; +namespace Modules\Analytics\Models; -use Analytics\Entities\AnalyticsWebsiteByReferer; use CodeIgniter\Model; +use Modules\Analytics\Entities\AnalyticsWebsiteByReferer; class AnalyticsWebsiteByRefererModel extends Model { @@ -23,7 +23,7 @@ class AnalyticsWebsiteByRefererModel extends Model protected $table = 'analytics_website_by_referer'; /** - * @var string + * @var class-string */ protected $returnType = AnalyticsWebsiteByReferer::class; @@ -50,7 +50,7 @@ class AnalyticsWebsiteByRefererModel extends Model ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneWeekAgo, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -58,6 +58,7 @@ class AnalyticsWebsiteByRefererModel extends Model cache() ->save("{$podcastId}_analytics_website_by_referer", $found, 600); } + return $found; } @@ -72,11 +73,11 @@ class AnalyticsWebsiteByRefererModel extends Model ! ($found = cache("{$podcastId}_analytics_website_by_domain_weekly")) ) { $oneWeekAgo = date('Y-m-d', strtotime('-1 week')); - $found = $this->select("SUBSTRING_INDEX(domain, '.', -2) as labels") + $found = $this->select('domain as labels') ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneWeekAgo, + 'date >' => $oneWeekAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -84,6 +85,7 @@ class AnalyticsWebsiteByRefererModel extends Model cache() ->save("{$podcastId}_analytics_website_by_domain_weekly", $found, 600); } + return $found; } @@ -98,11 +100,11 @@ class AnalyticsWebsiteByRefererModel extends Model ! ($found = cache("{$podcastId}_analytics_website_by_domain_yearly")) ) { $oneYearAgo = date('Y-m-d', strtotime('-1 year')); - $found = $this->select("SUBSTRING_INDEX(domain, '.', -2) as labels") + $found = $this->select('domain as labels') ->selectSum('hits', 'values') ->where([ 'podcast_id' => $podcastId, - 'date >' => $oneYearAgo, + 'date >' => $oneYearAgo, ]) ->groupBy('labels') ->orderBy('values', 'DESC') @@ -110,6 +112,7 @@ class AnalyticsWebsiteByRefererModel extends Model cache() ->save("{$podcastId}_analytics_website_by_domain_yearly", $found, 600); } + return $found; } } diff --git a/modules/Api/Rest/V1/Config/Registrar.php b/modules/Api/Rest/V1/Config/Registrar.php new file mode 100644 index 00000000..43814934 --- /dev/null +++ b/modules/Api/Rest/V1/Config/Registrar.php @@ -0,0 +1,22 @@ + + */ + public static function Filters(): array + { + return [ + 'aliases' => [ + 'rest-api' => ApiFilter::class, + ], + ]; + } +} diff --git a/modules/Api/Rest/V1/Config/RestApi.php b/modules/Api/Rest/V1/Config/RestApi.php new file mode 100644 index 00000000..836a8fb2 --- /dev/null +++ b/modules/Api/Rest/V1/Config/RestApi.php @@ -0,0 +1,36 @@ +group( + config('RestApi') + ->gateway . 'podcasts', + [ + 'namespace' => 'Modules\Api\Rest\V1\Controllers', + 'filter' => 'rest-api', + ], + static function ($routes): void { + $routes->get('/', 'PodcastController::list'); + $routes->get('(:num)', 'PodcastController::view/$1'); + $routes->get('(:any)', 'ExceptionController::notFound'); + }, +); + +$routes->group( + config('RestApi') + ->gateway . 'episodes', + [ + 'namespace' => 'Modules\Api\Rest\V1\Controllers', + 'filter' => 'rest-api', + ], + static function ($routes): void { + $routes->get('/', 'EpisodeController::list'); + $routes->post('/', 'EpisodeController::attemptCreate'); + $routes->post('(:num)/publish', 'EpisodeController::attemptPublish/$1'); + $routes->get('(:num)', 'EpisodeController::view/$1'); + $routes->get('(:any)', 'ExceptionController::notFound'); + }, +); diff --git a/modules/Api/Rest/V1/Config/Services.php b/modules/Api/Rest/V1/Config/Services.php new file mode 100644 index 00000000..40806e82 --- /dev/null +++ b/modules/Api/Rest/V1/Config/Services.php @@ -0,0 +1,20 @@ +initialize(); + } + + public function list(): ResponseInterface + { + $query = $this->request->getGet('query'); + $order = $this->request->getGet('order') ?? 'newest'; + $podcastIds = $this->request->getGet('podcastIds'); + + $builder = (new EpisodeModel()); + + if ($podcastIds !== null) { + $builder->whereIn('podcast_id', explode(',', (string) $podcastIds)); + } + + if ($query !== null) { + $builder->fullTextSearch($query); + + if ($order === 'search') { + $builder->orderBy('(episodes_score + podcasts_score)', 'desc'); + } + } + + if ($order === 'newest') { + $builder->orderBy('episodes.created_at', 'desc'); + } + + /** @var array $data */ + $data = $builder->findAll( + (int) ($this->request->getGet('limit') ?? config('RestApi')->limit), + (int) $this->request->getGet('offset'), + ); + + array_map(static function (Episode $episode): void { + self::mapEpisode($episode); + }, $data); + + return $this->respond($data); + } + + public function view(int $id): ResponseInterface + { + $episode = new EpisodeModel() + ->getEpisodeById($id); + + if (! $episode instanceof Episode) { + return $this->failNotFound('Episode not found'); + } + + // @phpstan-ignore-next-line + return $this->respond(static::mapEpisode($episode)); + } + + public function attemptCreate(): ResponseInterface + { + $rules = [ + 'created_by' => 'required|is_natural_no_zero', + 'updated_by' => 'required|is_natural_no_zero', + 'title' => 'required', + 'slug' => 'required|max_length[128]', + 'podcast_id' => 'required|is_natural_no_zero', + 'audio_file' => 'uploaded[audio_file]|ext_in[audio_file,mp3,m4a]', + 'cover' => 'permit_empty|is_image[cover]|ext_in[cover,jpg,jpeg,png]|min_dims[cover,1400,1400]|is_image_ratio[cover,1,1]', + 'transcript_file' => 'permit_empty|ext_in[transcript_file,srt,vtt]', + 'chapters_file' => 'permit_empty|ext_in[chapters_file,json]|is_json[chapters_file]', + 'transcript-choice' => 'permit_empty|in_list[upload-file,remote-url]', + 'chapters-choice' => 'permit_empty|in_list[upload-file,remote-url]', + ]; + + if (! $this->validate($rules)) { + return $this->failValidationErrors(array_values($this->validator->getErrors())); + } + + $podcastId = (int) $this->request->getPost('podcast_id'); + + $podcast = new PodcastModel() + ->getPodcastById($podcastId); + + if (! $podcast instanceof Podcast) { + return $this->failNotFound('Podcast not found'); + } + + $createdByUserId = (int) $this->request->getPost('created_by'); + + $userModel = new UserModel(); + $createdByUser = $userModel->find($createdByUserId); + + if (! $createdByUser) { + return $this->failNotFound('User not found'); + } + + $updatedByUserId = (int) $this->request->getPost('updated_by'); + + $updatedByUser = $userModel->find($updatedByUserId); + + if (! $updatedByUser) { + return $this->failNotFound('Updated by user not found'); + } + + if ($podcast->type === 'serial' && $this->request->getPost('type') === 'full') { + $rules['episode_number'] = 'required'; + } + + if (! $this->validate($rules)) { + return $this->failValidationErrors(array_values($this->validator->getErrors())); + } + + $validData = $this->validator->getValidated(); + + if (new EpisodeModel() + ->where([ + 'slug' => $validData['slug'], + 'podcast_id' => $podcast->id, + ]) + ->first() instanceof Episode) { + return $this->fail('An episode with the same slug already exists in this podcast.', 409); + } + + $newEpisode = new Episode([ + 'created_by' => $createdByUserId, + 'updated_by' => $updatedByUserId, + 'podcast_id' => $podcast->id, + 'title' => $validData['title'], + 'slug' => $validData['slug'], + 'guid' => null, + 'audio' => $this->request->getFile('audio_file'), + 'cover' => $this->request->getFile('cover'), + 'description_markdown' => $this->request->getPost('description'), + 'location' => in_array($this->request->getPost('location_name'), ['', null], true) + ? null + : new Location($this->request->getPost('location_name')), + 'parental_advisory' => $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null, + 'number' => $this->request->getPost('episode_number') ? (int) $this->request->getPost( + 'episode_number', + ) : null, + 'season_number' => $this->request->getPost('season_number') ? (int) $this->request->getPost( + 'season_number', + ) : null, + 'type' => $this->request->getPost('type'), + 'is_blocked' => $this->request->getPost('block') === 'yes', + 'custom_rss_string' => $this->request->getPost('custom_rss'), + 'is_premium' => $this->request->getPost('premium') === 'yes', + 'published_at' => null, + ]); + + $transcriptChoice = $this->request->getPost('transcript-choice'); + if ($transcriptChoice === 'upload-file') { + $newEpisode->setTranscript($this->request->getFile('transcript_file')); + } elseif ($transcriptChoice === 'remote-url') { + $newEpisode->transcript_remote_url = $this->request->getPost( + 'transcript_remote_url', + ) === '' ? null : $this->request->getPost('transcript_remote_url'); + } + + $chaptersChoice = $this->request->getPost('chapters-choice'); + if ($chaptersChoice === 'upload-file') { + $newEpisode->setChapters($this->request->getFile('chapters_file')); + } elseif ($chaptersChoice === 'remote-url') { + $newEpisode->chapters_remote_url = $this->request->getPost( + 'chapters_remote_url', + ) === '' ? null : $this->request->getPost('chapters_remote_url'); + } + + $episodeModel = new EpisodeModel(); + if (($newEpisodeId = (int) $episodeModel->insert($newEpisode, true)) === 0) { + return $this->fail(array_values($episodeModel->errors()), 400); + } + + $episode = $episodeModel->find($newEpisodeId) + ->toRawArray(); + + return $this->respond($episode); + } + + public function attemptPublish(int $id): ResponseInterface + { + $episodeModel = new EpisodeModel(); + $episode = $episodeModel->getEpisodeById($id); + + if (! $episode instanceof Episode) { + return $this->failNotFound('Episode not found'); + } + + if ($episode->publication_status !== 'not_published') { + return $this->fail('Episode is already published or scheduled for publication', 409); + } + + $rules = [ + 'publication_method' => 'required', + 'created_by' => 'required|is_natural_no_zero', + ]; + + if (! $this->validate($rules)) { + return $this->failValidationErrors(array_values($this->validator->getErrors())); + } + + if ($this->request->getPost('publication_method') === 'schedule') { + $rules['scheduled_publication_date'] = 'required|valid_date[Y-m-d H:i]'; + } + + if (! $this->validate($rules)) { + return $this->failValidationErrors(array_values($this->validator->getErrors())); + } + + $createdByUserId = (int) $this->request->getPost('created_by'); + + $userModel = new UserModel(); + $createdByUser = $userModel->find($createdByUserId); + + if (! $createdByUser) { + return $this->failNotFound('User not found'); + } + + $validData = $this->validator->getValidated(); + + $db = db_connect(); + $db->transStart(); + + $newPost = new Post([ + 'actor_id' => $episode->podcast->actor_id, + 'episode_id' => $episode->id, + 'message' => $this->request->getPost('message') ?? '', + 'created_by' => $createdByUserId, + ]); + + $clientTimezone = $this->request->getPost('client_timezone') ?? app_timezone(); + + if ($episode->podcast->publication_status === 'published') { + $publishMethod = $validData['publication_method']; + if ($publishMethod === 'schedule') { + $scheduledPublicationDate = $validData['scheduled_publication_date'] ?? null; + if ($scheduledPublicationDate) { + $episode->published_at = Time::createFromFormat( + 'Y-m-d H:i', + $scheduledPublicationDate, + $clientTimezone, + )->setTimezone(app_timezone()); + } else { + $db->transRollback(); + return $this->fail('Scheduled publication date is required', 400); + } + } else { + $episode->published_at = Time::now(); + } + } elseif ($episode->podcast->publication_status === 'scheduled') { + // podcast publication date has already been set + $episode->published_at = $episode->podcast->published_at->addSeconds(1); + } else { + $episode->published_at = Time::now(); + } + + $newPost->published_at = $episode->published_at; + + $postModel = new PostModel(); + if (! $postModel->addPost($newPost)) { + $db->transRollback(); + return $this->fail(array_values($postModel->errors()), 400); + } + + if (! $episodeModel->update($episode->id, $episode)) { + $db->transRollback(); + return $this->fail(array_values($episodeModel->errors()), 400); + } + + $db->transComplete(); + + // @phpstan-ignore-next-line + return $this->respond(self::mapEpisode($episode)); + } + + protected static function mapEpisode(Episode $episode): Episode + { + $episode->cover_url = $episode->getCover() + ->file_url; + $episode->duration = round($episode->audio->duration); + + return $episode; + } +} diff --git a/modules/Api/Rest/V1/Controllers/ExceptionController.php b/modules/Api/Rest/V1/Controllers/ExceptionController.php new file mode 100644 index 00000000..3f1cd7f0 --- /dev/null +++ b/modules/Api/Rest/V1/Controllers/ExceptionController.php @@ -0,0 +1,15 @@ +failNotFound('Podcast not found'); + } +} diff --git a/modules/Api/Rest/V1/Controllers/PodcastController.php b/modules/Api/Rest/V1/Controllers/PodcastController.php new file mode 100644 index 00000000..8daf7c33 --- /dev/null +++ b/modules/Api/Rest/V1/Controllers/PodcastController.php @@ -0,0 +1,59 @@ +initialize(); + } + + public function list(): ResponseInterface + { + /** @var array $data */ + $data = new PodcastModel() + ->findAll(); + array_map(static function (Podcast $podcast): void { + self::mapPodcast($podcast); + }, $data); + return $this->respond($data); + } + + public function view(int $id): ResponseInterface + { + $podcast = new PodcastModel() + ->getPodcastById($id); + if (! $podcast instanceof Podcast) { + return $this->failNotFound('Podcast not found'); + } + + // @phpstan-ignore-next-line + return $this->respond(self::mapPodcast($podcast)); + } + + protected static function mapPodcast(Podcast $podcast): Podcast + { + $podcast->feed_url = $podcast->getFeedUrl(); + $podcast->actor_display_name = $podcast->getActor() + ->display_name; + $podcast->cover_url = $podcast->getCover() + ->file_url; + + $categories = [$podcast->getCategory(), ...$podcast->getOtherCategories()]; + + foreach ($categories as $category) { + $category->translated = lang('Podcast.category_options.' . $category->code); + } + + $podcast->categories = $categories; + + return $podcast; + } +} diff --git a/modules/Api/Rest/V1/Core/RestApiExceptions.php b/modules/Api/Rest/V1/Core/RestApiExceptions.php new file mode 100644 index 00000000..7d132aea --- /dev/null +++ b/modules/Api/Rest/V1/Core/RestApiExceptions.php @@ -0,0 +1,35 @@ + $statusCode, + 'error' => $statusCode, + 'messages' => [ + 'error' => 'Unexpected error', + ], + ]; + if (ENVIRONMENT === 'development') { + $data['messages'] = array_merge($data['messages'], [ + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'trace' => $exception->getTrace(), + ]); + } + + echo json_encode($data); + } +} diff --git a/modules/Api/Rest/V1/Filters/ApiFilter.php b/modules/Api/Rest/V1/Filters/ApiFilter.php new file mode 100644 index 00000000..8bb25935 --- /dev/null +++ b/modules/Api/Rest/V1/Filters/ApiFilter.php @@ -0,0 +1,80 @@ +enabled) { + throw PageNotFoundException::forPageNotFound(); + } + + if ($request->getMethod() === 'POST' && ! $restApiConfig->basicAuth) { + /** @var Response $response */ + $response = service('response'); + $response->setStatusCode(401); + return $response; + } + + if ($restApiConfig->basicAuth) { + /** @var Response $response */ + $response = service('response'); + if (! $request->hasHeader('Authorization')) { + $response->setStatusCode(401); + + return $response; + } + + $authHeader = $request->getHeaderLine('Authorization'); + if (! str_starts_with($authHeader, 'Basic ')) { + $response->setStatusCode(401); + + return $response; + } + + $auth_token = base64_decode(substr($authHeader, 6), true); + + [$username, $password] = explode(':', (string) $auth_token); + + if (! ($username === $restApiConfig->basicAuthUsername && $password === $restApiConfig->basicAuthPassword)) { + $response->setStatusCode(401); + + return $response; + } + } + + return null; + } + + /** + * @param string[]|null $arguments + * + * @return ResponseInterface|null + */ + #[Override] + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + return null; + } +} diff --git a/modules/Api/Rest/V1/schema.yaml b/modules/Api/Rest/V1/schema.yaml new file mode 100644 index 00000000..9c7a0220 --- /dev/null +++ b/modules/Api/Rest/V1/schema.yaml @@ -0,0 +1,530 @@ +openapi: 3.1.0 +info: + version: 1.0.0 + title: Castopod API + description: |- + The Castopod API offers you a programmatic way to integrate your Podcasts and + Episodes in your apps and help you automate creation and publishing. + + ⚠️ **The API is disabled by default.** + + You may add the following feature flag in your `.env` to activate it: + + ```ini + restapi.enabled=true + ``` + + Operations to add or publish episodes require you to setup basic authentication + in your `.env`: + + ```ini + restapi.basicAuth=true + restapi.basicAuthUsername="YOUR_BASIC_AUTH_USERNAME" + restapi.basicAuthPassword="YOUR_BASIC_AUTH_PASSWORD" + ``` + + With BasicAuth enabled, your requests must include the `Authorization` header + with the username and password you have set previously: + + ``` + "Authorization": "Basic username:password" + ``` + + license: + name: AGPL v3 + url: https://code.castopod.org/adaures/castopod/-/blob/develop/LICENSE.md +paths: + /podcasts: + get: + summary: Get all podcasts + operationId: get-all-podcasts + responses: + "200": + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Podcast" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /podcasts/{podcastId}: + parameters: + - name: podcastId + in: path + description: The id of the podcast to retrieve + required: true + schema: + type: integer + format: int64 + get: + summary: Get podcast by ID + description: Returns a single podcast + operationId: get-podcast-by-id + responses: + "200": + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/Podcast" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /episodes: + get: + summary: Get all episodes + operationId: get-all-episodes + responses: + "200": + description: Object of episodes + content: + application/json: + schema: + type: "array" + items: + $ref: "#/components/schemas/Episode" + default: + description: Unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Add a new episode + operationId: add-episode + requestBody: + description: Episode object that needs to be added + required: true + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/EpisodeCreateRequest" + responses: + "201": + description: Episode created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/Episode" + default: + description: Unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /episodes/{episodeId}: + parameters: + - name: episodeId + in: path + description: The id of the episode to retrieve + required: true + schema: + type: integer + format: int64 + get: + summary: Get episode by ID + description: Returns a single episode + operationId: get-episode-by-id + responses: + "200": + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Episode" + default: + description: Unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /episodes/{episodeId}/publish: + post: + summary: Publish an episode + operationId: publish-episode + parameters: + - name: episodeId + in: path + description: The id of the episode to publish + required: true + schema: + type: integer + format: int64 + requestBody: + description: Publish parameters + required: true + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/EpisodePublishRequest" + responses: + "200": + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/Episode" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Podcast: + type: object + required: + - id + - guid + - actor_id + - handle + - title + - description_markdown + - description_html + - cover_id + - language_code + - category_id + - owner_name + - owner_email + - type + - is_blocked + - is_completed + - is_locked + - is_published_on_hubs + - created_by + - updated_by + - created_at + - updated_at + - feed_url + properties: + id: + type: integer + format: int64 + guid: + type: string + maxLength: 36 + actor_id: + type: integer + format: int64 + handle: + type: string + maxLength: 32 + title: + type: string + maxLength: 128 + description_markdown: + type: string + description_html: + type: string + cover_id: + type: integer + format: int64 + banner_id: + type: integer + format: int64 + language_code: + type: string + maxLength: 2 + category_id: + type: integer + format: int64 + minimum: 1 + parental_advisory: + type: string + enum: + - clean + - explicit + owner_name: + type: string + maxLength: 128 + owner_email: + type: string + maxLength: 255 + publisher: + type: string + maxLength: 128 + type: + type: string + enum: + - episodic + - serial + copyright: + type: string + maxLength: 128 + episode_description_footer_markdown: + type: string + episode_description_footer_html: + type: string + is_blocked: + type: integer + format: int32 + enum: + - 0 + - 1 + is_completed: + type: integer + format: int32 + enum: + - 0 + - 1 + is_locked: + type: integer + format: int32 + enum: + - 0 + - 1 + imported_feed_url: + type: string + maxLength: 512 + new_feed_url: + type: string + maxLength: 512 + location_name: + type: string + maxLength: 128 + location_geo: + type: string + maxLength: 32 + location_osm: + type: string + maxLength: 12 + custom_rss: + type: string + is_published_on_hubs: + type: integer + format: int32 + enum: + - 0 + - 1 + partner_id: + type: string + maxLength: 32 + partner_link_url: + type: string + maxLength: 512 + partner_image_url: + type: string + maxLength: 512 + created_by: + type: integer + format: int64 + updated_by: + type: integer + format: int64 + created_at: + type: object + properties: + date: + type: string + format: date-time + timezone_type: + type: integer + format: int32 + timezone: + type: string + updated_at: + type: object + properties: + date: + type: string + format: date-time + timezone_type: + type: integer + format: int32 + timezone: + type: string + feed_url: + type: string + Episode: + type: object + required: + - id + - title + - slug + - podcast_id + - created_by + - updated_by + - created_at + - updated_at + properties: + id: + type: integer + format: int64 + title: + type: string + slug: + type: string + podcast_id: + type: integer + format: int64 + description_markdown: + type: string + description_html: + type: string + audio_url: + type: string + format: uri + cover_url: + type: string + format: uri + duration: + type: integer + format: int32 + published_at: + type: string + format: date-time + created_by: + type: integer + format: int64 + updated_by: + type: integer + format: int64 + EpisodeCreateRequest: + type: object + required: + - user_id + - updated_by + - title + - slug + - podcast_id + - audio_file + properties: + user_id: + type: integer + format: int64 + description: ID of the user creating the episode + updated_by: + type: integer + format: int64 + description: ID of the user updating the episode + title: + type: string + description: Title of the episode + slug: + type: string + description: URL-friendly slug of the episode + podcast_id: + type: integer + format: int64 + description: ID of the podcast the episode belongs to + audio_file: + type: string + format: binary + description: Audio file for the episode + cover: + type: string + format: binary + description: Cover image for the episode + description: + type: string + description: Description of the episode + location_name: + type: string + description: Location associated with the episode + parental_advisory: + type: string + enum: + - clean + - explicit + description: Parental advisory rating + episode_number: + type: integer + format: int32 + description: Episode number (for serial podcasts) + season_number: + type: integer + format: int32 + description: Season number (for serial podcasts) + type: + type: string + enum: + - full + - trailer + - bonus + description: Type of episode + block: + type: string + enum: + - "yes" + - "no" + description: Block episode from being published + custom_rss: + type: string + description: Custom RSS content + premium: + type: string + enum: + - "yes" + - "no" + description: Mark episode as premium content + transcript-choice: + type: string + enum: + - upload-file + - remote-url + description: Transcript source choice + transcript_file: + type: string + format: binary + description: Transcript file + transcript_remote_url: + type: string + format: uri + description: Remote URL for transcript + chapters-choice: + type: string + enum: + - upload-file + - remote-url + description: Chapters source choice + chapters_file: + type: string + format: binary + description: Chapters file + chapters_remote_url: + type: string + format: uri + description: Remote URL for chapters + EpisodePublishRequest: + type: object + required: + - publication_method + properties: + publication_method: + type: string + enum: + - now + - schedule + - with_podcast + description: Method of publication + scheduled_publication_date: + type: string + format: date-time + description: Scheduled date and time for publication + client_timezone: + type: string + description: Timezone of the client + Error: + type: object + properties: + status: + type: integer + format: int32 + error: + type: integer + format: int32 + messages: + type: object + properties: + error: + type: string diff --git a/modules/Auth/Auth.php b/modules/Auth/Auth.php new file mode 100644 index 00000000..83403106 --- /dev/null +++ b/modules/Auth/Auth.php @@ -0,0 +1,46 @@ +routes($routes); + * - auth()->routes($routes, ['except' => ['login', 'register']]) + * + * @param array{except?:list} $config + */ + #[Override] + public function routes(RouteCollection &$routes, array $config = []): void + { + $authRoutes = config('AuthRoutes') + ->routes; + + $routes->group(config('Auth')->gateway, [ + 'namespace' => 'Modules\Auth\Controllers', + ], static function (RouteCollection $routes) use ($authRoutes, $config): void { + foreach ($authRoutes as $name => $row) { + if (! isset($config['except']) || ! in_array($name, $config['except'], true)) { + foreach ($row as $params) { + $options = isset($params[3]) + ? [ + 'as' => $params[3], + ] + : null; + $routes->{$params[0]}($params[1], $params[2], $options); + } + } + } + }); + } +} diff --git a/modules/Auth/Commands/RolesDoc.php b/modules/Auth/Commands/RolesDoc.php new file mode 100644 index 00000000..84d7b941 --- /dev/null +++ b/modules/Auth/Commands/RolesDoc.php @@ -0,0 +1,196 @@ + + */ + private const array COMMENT_BLOCK_IDS = [ + 'instance_roles' => 'AUTH-INSTANCE-ROLES-LIST', + 'instance_permissions' => 'AUTH-INSTANCE-PERMISSIONS-LIST', + 'podcast_roles' => 'AUTH-PODCAST-ROLES-LIST', + 'podcast_permissions' => 'AUTH-PODCAST-PERMISSIONS-LIST', + ]; + + /** + * @var string + */ + protected $group = 'auth'; + + /** + * @var string + */ + protected $name = 'auth:generate-doc'; + + /** + * @var string + */ + protected $description = 'Generates the html table references for roles and permissions in the docs.'; + + #[Override] + public function run(array $params): void + { + // loop over all files in path + $files = glob(ROOTPATH . 'docs/src/content/docs/**/getting-started/auth.mdx'); + + if (! $files) { + $files = []; + } + + CLI::write(implode(PHP_EOL, $files)); + + if ($files === []) { + return; + } + + foreach ($files as $file) { + $locale = $this->detectLocaleFromPath($file); + service('language') + ->setLocale($locale); + + $authGroups = new AuthGroups(); + + $fileContents = file_get_contents($file); + + foreach (self::COMMENT_BLOCK_IDS as $key => $block_id) { + $pattern = '/(\{\/\*\s' . $block_id . ':START.*\*\/\})[\S\s]*(\{\/\*\s' . $block_id . ':END.*\*\/\})/'; + + $handleInjectMethod = 'handle' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key))); + + $fileContents = $this->{$handleInjectMethod}($authGroups, $fileContents, $pattern); + } + + // Write the contents back to the file + file_put_contents($file, $fileContents); + } + } + + protected function handleInstanceRoles(AuthGroups $authGroups, string $fileContents, string $pattern): string + { + $instanceMatrix = $authGroups->matrix; + return $this->renderCommentBlock( + $fileContents, + $pattern, + ['role', 'description', 'permissions'], + $authGroups->instanceGroups, + static function ($table, $key, array $value) use ($instanceMatrix): void { + $table->addRow($value['title'], $value['description'], implode(', ', $instanceMatrix[$key])); + }, + ); + } + + protected function handleInstancePermissions(AuthGroups $authGroups, string $fileContents, string $pattern): string + { + return $this->renderCommentBlock( + $fileContents, + $pattern, + ['permission', 'description'], + $authGroups->instancePermissions, + static function ($table, $key, $value): void { + $table->addRow($key, $value); + }, + ); + } + + protected function handlePodcastRoles(AuthGroups $authGroups, string $fileContents, string $pattern): string + { + $podcastMatrix = $authGroups->podcastMatrix; + return $this->renderCommentBlock( + $fileContents, + $pattern, + ['role', 'description', 'permissions'], + $authGroups->podcastGroups, + static function ($table, $key, array $value) use ($podcastMatrix): void { + $table->addRow($value['title'], $value['description'], implode(', ', $podcastMatrix[$key])); + }, + ); + } + + protected function handlePodcastPermissions(AuthGroups $authGroups, string $fileContents, string $pattern): string + { + return $this->renderCommentBlock( + $fileContents, + $pattern, + ['permission', 'description'], + $authGroups->podcastPermissions, + static function ($table, $key, $value): void { + $table->addRow($key, $value); + }, + ); + } + + /** + * @param array $tableHeading + * @param array|array> $data + */ + private function renderCommentBlock( + string $fileContents, + string $pattern, + array $tableHeading, + array $data, + Closure $callback, + ): string { + // check if it has the start and end comments to insert roles table + // looking for and + + $hasInstanceInsertComments = preg_match($pattern, $fileContents); + + if (! $hasInstanceInsertComments) { + return $fileContents; + } + + // prepare role table + $table = new Table(); + $table->setHeading($tableHeading); + + foreach ($data as $key => $value) { + $callback($table, $key, $value); + } + + $converter = new HtmlConverter(); + $converter->getEnvironment() + ->addConverter(new TableConverter()); + $markdownTable = str_replace(['{', '}'], ['\{', '\}'], $converter->convert($table->generate())); + + // insert table between block comments + $newFileContents = preg_replace( + $pattern, + '${1}' . PHP_EOL . PHP_EOL . $markdownTable . PHP_EOL . PHP_EOL . '${2}', + $fileContents, + ); + + if ($newFileContents === null) { + return $fileContents; + } + + return $newFileContents; + } + + private function detectLocaleFromPath(string $fileKey): string + { + preg_match( + '~docs\/src\/content\/docs\/(?:([a-z]{2}(?:-[A-Za-z]{2,})?)\/)getting-started\/auth\.mdx~', + $fileKey, + $match, + ); + + if ($match === []) { + return 'en'; + } + + return $match[1]; + } +} diff --git a/modules/Auth/Config/Auth.php b/modules/Auth/Config/Auth.php new file mode 100644 index 00000000..f5fc2c68 --- /dev/null +++ b/modules/Auth/Config/Auth.php @@ -0,0 +1,176 @@ + + */ + public array $views = [ + 'login' => 'login', + 'register' => 'register', + 'layout' => '_layout', + 'action_email_2fa' => 'email_2fa_show', + 'action_email_2fa_verify' => 'email_2fa_verify', + 'action_email_2fa_email' => 'emails/email_2fa_email', + 'action_email_activate_show' => 'email_activate_show', + 'action_email_activate_email' => 'emails/email_activate_email', + 'magic-link-login' => 'magic_link_form', + 'magic-link-message' => 'magic_link_message', + 'magic-link-email' => 'emails/magic_link_email', + 'magic-link-set-password' => 'magic_link_set_password', + 'welcome-email' => 'emails/welcome_email', + ]; + + /** + * -------------------------------------------------------------------- + * Redirect urLs + * -------------------------------------------------------------------- + * The default URL that a user will be redirected to after + * various auth actions. If you need more flexibility you can + * override the `getUrl()` method to apply any logic you may need. + * + * @var array + */ + public array $redirects = [ + 'register' => '/', + 'login' => '/', + 'logout' => 'login', + 'force_reset' => '/', + 'permission_denied' => '/', + 'group_denied' => '/', + ]; + + /** + * -------------------------------------------------------------------- + * Authentication Actions + * -------------------------------------------------------------------- + * Specifies the class that represents an action to take after + * the user logs in or registers a new account at the site. + * + * You must register actions in the order of the actions to be performed. + * + * Available actions with Shield: + * - register: 'CodeIgniter\Shield\Authentication\Actions\EmailActivator' + * - login: 'CodeIgniter\Shield\Authentication\Actions\Email2FA' + * + * @var array|null> + */ + public array $actions = [ + 'register' => null, + 'login' => null, + ]; + + /** + * -------------------------------------------------------------------- + * Allow Registration + * -------------------------------------------------------------------- + * Determines whether users can register for the site. + */ + public bool $allowRegistration = false; + + /** + * -------------------------------------------------------------------- + * Allow Two-Factor Authentication + * -------------------------------------------------------------------- + * Determines whether email 2FA is enabled. + */ + public bool $enable2FA = false; + + /** + * -------------------------------------------------------------------- + * Welcome Link Lifetime + * -------------------------------------------------------------------- + * Specifies the amount of time, in seconds, that a welcome link is valid. + * You can use Time Constants or any desired number. + */ + public int $welcomeLinkLifetime = 48 * HOUR; + + /** + * -------------------------------------------------------------------- + * User Provider + * -------------------------------------------------------------------- + * The name of the class that handles user persistence. + * By default, this is the included UserModel, which + * works with any of the database engines supported by CodeIgniter. + * You can change it as long as they adhere to the + * CodeIgniter\Shield\Models\UserModel. + * + * @var class-string + */ + public string $userProvider = UserModel::class; + + /** + * -------------------------------------------------------------------------- + * Auth gateway + * -------------------------------------------------------------------------- + * Defines a base route for all authentication related pages + */ + public string $gateway = 'cp-auth'; + + public function __construct() + { + parent::__construct(); + + $adminGateway = config('Admin') + ->gateway; + + $this->redirects = [ + 'register' => $adminGateway, + 'login' => $adminGateway, + 'logout' => $adminGateway, + 'force_reset' => $adminGateway, + 'permission_denied' => $adminGateway, + 'group_denied' => $adminGateway, + ]; + + // FIXME: enable2FA config can only be updated in the .env + // Using the settings service to have it set in the db causes infinite loop. + if ($this->enable2FA) { + $this->actions['login'] = Email2FA::class; + } + } + + /** + * Returns the URL that a user should be redirected to after a successful login. + * + * Redirects to the set-password form if magicLogin + */ + #[Override] + public function loginRedirect(): string + { + if (! session('magicLogin')) { + return $this->getUrl(setting('Auth.redirects')['login']); + } + + // activate user upon magic-link login as it is done via email + if (! auth()->user()->active) { + /** @var AuthenticatorInterface $authenticator */ + $authenticator = auth('session') + ->getAuthenticator(); + + $user = $authenticator->getUser(); + + if ($user instanceof User) { + // Set the user active now + $user->activate(); + } + } + + // prompt user to change their password + return $this->getUrl(route_to('magic-link-set-password')); + } +} diff --git a/modules/Auth/Config/AuthGroups.php b/modules/Auth/Config/AuthGroups.php new file mode 100644 index 00000000..5bb64b88 --- /dev/null +++ b/modules/Auth/Config/AuthGroups.php @@ -0,0 +1,290 @@ +attempt($credentials); + * + * @var array> + */ + public array $groups = []; + + /** + * -------------------------------------------------------------------- + * Permissions + * -------------------------------------------------------------------- + * The available permissions in the system. Each system is defined + * where the key is the + * + * If a permission is not listed here it cannot be used. + * + * @var array + */ + public array $permissions = []; + + /** + * -------------------------------------------------------------------- + * Permissions Matrix + * -------------------------------------------------------------------- + * Maps permissions to groups. + * @var array> + */ + public array $matrix = []; + + /** + * @var array> + */ + public array $instanceGroups = []; + + /** + * @var array + */ + public array $instancePermissions = []; + + /** + * @var array> + */ + public array $podcastGroups = []; + + /** + * @var array + */ + public array $podcastPermissions = []; + + /** + * @var string[] + */ + public array $instanceBaseGroups = ['superadmin', 'manager', 'podcaster']; + + /** + * @var string[] + */ + public array $instanceBasePermissions = [ + 'admin.access', + 'admin.settings', + 'plugins.manage', + 'users.manage', + 'persons.manage', + 'pages.manage', + 'podcasts.view', + 'podcasts.create', + 'podcasts.import', + 'fediverse.manage-blocks', + ]; + + /** + * @var array> + */ + public array $instanceMatrix = [ + 'superadmin' => [ + 'admin.*', + 'plugins.*', + 'podcasts.*', + 'users.manage', + 'persons.manage', + 'pages.manage', + 'fediverse.manage-blocks', + ], + 'manager' => ['podcasts.create', 'podcasts.import', 'persons.manage', 'pages.manage'], + 'podcaster' => ['admin.access'], + ]; + + /** + * @var string[] + */ + public array $podcastBaseGroups = ['admin', 'editor', 'author', 'guest']; + + /** + * @var string[] + */ + public array $podcastBasePermissions = [ + 'view', + 'edit', + 'delete', + 'manage-import', + 'manage-persons', + 'manage-subscriptions', + 'manage-contributors', + 'manage-platforms', + 'manage-publications', + 'manage-notifications', + 'interact-as', + 'episodes.view', + 'episodes.create', + 'episodes.edit', + 'episodes.delete', + 'episodes.manage-persons', + 'episodes.manage-clips', + 'episodes.manage-publications', + 'episodes.manage-comments', + ]; + + /** + * @var array + */ + public array $podcastMatrix = [ + 'admin' => ['*'], + 'editor' => [ + 'view', + 'edit', + 'manage-import', + 'manage-persons', + 'manage-platforms', + 'manage-publications', + 'manage-notifications', + 'interact-as', + 'episodes.view', + 'episodes.create', + 'episodes.edit', + 'episodes.delete', + 'episodes.manage-persons', + 'episodes.manage-clips', + 'episodes.manage-publications', + 'episodes.manage-comments', + ], + 'author' => [ + 'view', + 'manage-persons', + 'episodes.view', + 'episodes.create', + 'episodes.edit', + 'episodes.manage-persons', + 'episodes.manage-clips', + ], + 'guest' => ['view', 'episodes.view'], + ]; + + /** + * Fill groups, permissions and matrix based on + */ + public function __construct() + { + parent::__construct(); + + foreach ($this->instanceBaseGroups as $group) { + $this->instanceGroups[$group] = [ + 'title' => lang("Auth.instance_groups.{$group}.title"), + 'description' => lang("Auth.instance_groups.{$group}.description"), + ]; + } + + $this->groups = $this->instanceGroups; + + foreach ($this->instanceBasePermissions as $permission) { + $this->instancePermissions[$permission] = lang("Auth.instance_permissions.{$permission}"); + $this->permissions[$permission] = lang("Auth.instance_permissions.{$permission}"); + } + + $this->matrix = $this->instanceMatrix; + + $this->generateBasePodcastAuthorizations(); + + /** + * For each podcast, include podcast groups, permissions, and matrix into $groups, $permissions, and $matrix + * attributes. + */ + $podcasts = new PodcastModel() + ->findAll(); + foreach ($podcasts as $podcast) { + $this->generatePodcastAuthorizations($podcast->id); + } + } + + public function generateBasePodcastAuthorizations(): void + { + foreach ($this->podcastBaseGroups as $group) { + $this->podcastGroups[$group] = [ + 'title' => lang("Auth.podcast_groups.{$group}.title", [ + 'id' => '{id}', + ]), + 'description' => lang("Auth.podcast_groups.{$group}.description", [ + 'id' => '{id}', + ]), + ]; + } + + foreach ($this->podcastBasePermissions as $permission) { + $this->podcastPermissions[$permission] = lang("Auth.podcast_permissions.{$permission}", [ + 'id' => '{id}', + ]); + $this->permissions[$permission] = lang("Auth.podcast_permissions.{$permission}", [ + 'id' => '{id}', + ]); + } + } + + public function generatePodcastAuthorizations(int $podcastId): void + { + foreach ($this->podcastBaseGroups as $group) { + $podcastGroup = 'podcast#' . $podcastId . '-' . $group; + $this->groups[$podcastGroup] = [ + 'title' => lang("Auth.podcast_groups.{$group}.title", [ + 'id' => $podcastId, + ]), + 'description' => lang("Auth.podcast_groups.{$group}.description", [ + 'id' => $podcastId, + ]), + ]; + } + + foreach ($this->podcastBasePermissions as $permission) { + $podcastPermission = 'podcast#' . $podcastId . '.' . $permission; + $this->permissions[$podcastPermission] = lang("Auth.podcast_permissions.{$permission}", [ + 'id' => $podcastId, + ]); + } + + foreach ($this->podcastMatrix as $group => $permissionWildcards) { + $podcastGroup = 'podcast#' . $podcastId . '-' . $group; + foreach ($permissionWildcards as $permissionWildcard) { + $podcastPermissionWildcard = 'podcast#' . $podcastId . '.' . $permissionWildcard; + $this->matrix[$podcastGroup][] = $podcastPermissionWildcard; + } + } + } +} diff --git a/modules/Auth/Config/AuthRoutes.php b/modules/Auth/Config/AuthRoutes.php new file mode 100644 index 00000000..8e7540a2 --- /dev/null +++ b/modules/Auth/Config/AuthRoutes.php @@ -0,0 +1,45 @@ +>> + */ + public array $routes = [ + 'register' => [ + ['get', 'register', 'RegisterController::registerView', 'register'], + ['post', 'register', 'RegisterController::registerAction'], + ], + 'login' => [ + ['get', 'login', 'LoginController::loginView', 'login'], + ['post', 'login', 'LoginController::loginAction'], + ], + 'magic-link' => [ + [ + 'get', + 'login/magic-link', + 'MagicLinkController::loginView', + 'magic-link', // Route name + ], + ['post', 'login/magic-link', 'MagicLinkController::loginAction'], + [ + 'get', + 'login/verify-magic-link', + 'MagicLinkController::verify', + 'verify-magic-link', // Route name + ], + ], + 'logout' => [['get', 'logout', 'LoginController::logoutAction', 'logout']], + 'auth-actions' => [ + ['get', 'auth/a/show', 'ActionController::show', 'auth-action-show'], + ['post', 'auth/a/handle', 'ActionController::handle', 'auth-action-handle'], + ['post', 'auth/a/verify', 'ActionController::verify', 'auth-action-verify'], + ], + ]; +} diff --git a/modules/Auth/Config/AuthToken.php b/modules/Auth/Config/AuthToken.php new file mode 100644 index 00000000..4f56dc76 --- /dev/null +++ b/modules/Auth/Config/AuthToken.php @@ -0,0 +1,123 @@ + + */ + public array $authenticatorHeader = [ + 'tokens' => 'Authorization', + 'hmac' => 'Authorization', + ]; + + /** + * -------------------------------------------------------------------- + * Unused Token Lifetime + * -------------------------------------------------------------------- + * Determines the amount of time, in seconds, that an unused token can + * be used. + */ + public int $unusedTokenLifetime = YEAR; + + /** + * -------------------------------------------------------------------- + * HMAC secret key byte size + * -------------------------------------------------------------------- + * Specify in integer the desired byte size of the + * HMAC SHA256 byte size + */ + public int $hmacSecretKeyByteSize = 32; + + /** + * -------------------------------------------------------------------- + * HMAC encryption Keys + * -------------------------------------------------------------------- + * This sets the key to be used when encrypting a user's HMAC Secret Key. + * + * 'keys' is an array of keys which will facilitate key rotation. Valid + * keyTitles must include only [a-zA-Z0-9_] and should be kept to a + * max of 8 characters. + * + * Each keyTitle is an associative array containing the required 'key' + * value, and the optional 'driver' and 'digest' values. If the + * 'driver' and 'digest' values are not specified, the default 'driver' + * and 'digest' values will be used. + * + * Old keys will are used to decrypt existing Secret Keys. It is encouraged + * to run 'php spark shield:hmac reencrypt' to update existing Secret + * Key encryptions. + * + * @see https://codeigniter.com/user_guide/libraries/encryption.html + * + * @var array|string + * + * NOTE: The value becomes temporarily a string when setting value as JSON + * from environment variable. + * + * [key_name => ['key' => key_value]] + * or [key_name => ['key' => key_value, 'driver' => driver, 'digest' => digest]] + */ + public $hmacEncryptionKeys = [ + 'k1' => [ + 'key' => '', + ], + ]; + + /** + * -------------------------------------------------------------------- + * HMAC Current Encryption Key Selector + * -------------------------------------------------------------------- + * This specifies which of the encryption keys should be used. + */ + public string $hmacEncryptionCurrentKey = 'k1'; + + /** + * -------------------------------------------------------------------- + * HMAC Encryption Key Driver + * -------------------------------------------------------------------- + * This specifies which of the encryption drivers should be used. + * + * Available drivers: + * - OpenSSL + * - Sodium + */ + public string $hmacEncryptionDefaultDriver = 'OpenSSL'; + + /** + * -------------------------------------------------------------------- + * HMAC Encryption Key Driver + * -------------------------------------------------------------------- + * THis specifies the type of encryption to be used. + * e.g. 'SHA512' or 'SHA256'. + */ + public string $hmacEncryptionDefaultDigest = 'SHA512'; +} diff --git a/modules/Auth/Config/Events.php b/modules/Auth/Config/Events.php new file mode 100644 index 00000000..36b0cf2a --- /dev/null +++ b/modules/Auth/Config/Events.php @@ -0,0 +1,14 @@ +routes($routes); + +// Admin routes for users and podcast contributors +$routes->group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\Auth\Controllers', + ], + static function ($routes): void { + $routes->get('magic-link-set-password', 'MagicLinkController::setPasswordView', [ + 'as' => 'magic-link-set-password', + ]); + $routes->post('magic-link-set-password', 'MagicLinkController::setPasswordAction'); + + $routes->post('interact-as-actor', 'InteractController::interactAsActorAction', [ + 'as' => 'interact-as-actor', + ]); + + // Users + $routes->group('users', static function ($routes): void { + $routes->get('/', 'UserController::list', [ + 'as' => 'user-list', + 'filter' => 'permission:users.manage', + ]); + $routes->get('new', 'UserController::createView', [ + 'as' => 'user-create', + 'filter' => 'permission:users.manage', + ]); + $routes->post('new', 'UserController::createAction', [ + 'filter' => 'permission:users.manage', + ]); + // User + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'UserController::view/$1', [ + 'as' => 'user-view', + 'filter' => 'permission:users.manage', + ]); + $routes->get('edit', 'UserController::editView/$1', [ + 'as' => 'user-edit', + 'filter' => 'permission:users.manage', + ]); + $routes->post('edit', 'UserController::editAction/$1', [ + 'filter' => 'permission:users.manage', + ]); + $routes->get('delete', 'UserController::delete/$1', [ + 'as' => 'user-delete', + 'filter' => 'permission:users.manage', + ]); + $routes->post('delete', 'UserController::deleteAction/$1', [ + 'as' => 'user-delete', + 'filter' => 'permission:users.manage', + ]); + }); + }); + // My account + $routes->group('my-account', static function ($routes): void { + $routes->get('/', 'MyAccountController', [ + 'as' => 'my-account', + ]); + $routes->get('change-password', 'MyAccountController::changePassword', [ + 'as' => 'change-password', + ],); + $routes->post('change-password', 'MyAccountController::changeAction'); + }); + + // Podcast contributors + $routes->group('podcasts/(:num)/contributors', static function ($routes): void { + $routes->get('/', 'ContributorController::list/$1', [ + 'as' => 'contributor-list', + 'filter' => 'permission:podcast$1.manage-contributors', + ]); + $routes->get('add', 'ContributorController::createView/$1', [ + 'as' => 'contributor-add', + 'filter' => 'permission:podcast$1.manage-contributors', + ]); + $routes->post( + 'add', + 'ContributorController::createAction/$1', + [ + 'filter' => 'permission:podcast$1.manage-contributors', + ], + ); + // Contributor + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'ContributorController::view/$1/$2', [ + 'as' => 'contributor-view', + 'filter' => 'permission:podcast$1.manage-contributors', + ]); + $routes->get( + 'edit', + 'ContributorController::editView/$1/$2', + [ + 'as' => 'contributor-edit', + 'filter' => 'permission:podcast$1.manage-contributors', + ], + ); + $routes->post( + 'edit', + 'ContributorController::editAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.manage-contributors', + ], + ); + $routes->get( + 'remove', + 'ContributorController::removeView/$1/$2', + [ + 'as' => 'contributor-remove', + 'filter' => 'permission:podcast$1.manage-contributors', + ], + ); + $routes->post( + 'remove', + 'ContributorController::removeAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.manage-contributors', + ], + ); + }); + }); + }, +); diff --git a/modules/Auth/Config/Services.php b/modules/Auth/Config/Services.php new file mode 100644 index 00000000..1ef66bae --- /dev/null +++ b/modules/Auth/Config/Services.php @@ -0,0 +1,26 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->podcast = $podcast; + + if (count($params) <= 1) { + return $this->{$method}(); + } + + if (($this->contributor = new UserModel()->getPodcastContributor( + (int) $params[1], + (int) $params[0], + )) instanceof User) { + return $this->{$method}(); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function list(): string + { + $data = [ + 'podcast' => $this->podcast, + ]; + + $this->setHtmlHead(lang('Contributor.podcast_contributors')); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + ]); + return view('contributor/list', $data); + } + + public function view(): string + { + $data = [ + 'podcast' => $this->podcast, + 'contributor' => new UserModel() + ->getPodcastContributor($this->contributor->id, $this->podcast->id), + ]; + + $this->setHtmlHead(lang('Contributor.view', [ + 'username' => esc($this->contributor->username), + 'podcastTitle' => esc($this->podcast->title), + ])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => $this->contributor->username, + ]); + return view('contributor/view', $data); + } + + public function createView(): string + { + helper('form'); + + $users = new UserModel() + ->findAll(); + $contributorOptions = array_reduce( + $users, + static function (array $result, User $user): array { + $result[] = [ + 'value' => $user->id, + 'label' => $user->username, + ]; + return $result; + }, + [], + ); + + $roles = setting('AuthGroups.podcastBaseGroups'); + $roleOptions = []; + array_walk( + $roles, + static function (string $role, $key) use (&$roleOptions): array { + $roleOptions[] = [ + 'value' => $role, + 'label' => lang('Auth.podcast_groups.' . $role . '.title'), + ]; + return $roleOptions; + }, + [], + ); + + $data = [ + 'podcast' => $this->podcast, + 'contributorOptions' => $contributorOptions, + 'roleOptions' => $roleOptions, + ]; + + $this->setHtmlHead(lang('Contributor.add_contributor', [esc($this->podcast->title)])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + ]); + return view('contributor/create', $data); + } + + public function createAction(): RedirectResponse + { + /** @var User $user */ + $user = new UserModel() + ->find((int) $this->request->getPost('user')); + + if (get_podcast_group($user, $this->podcast->id)) { + return redirect() + ->back() + ->withInput() + ->with('errors', [lang('Contributor.messages.alreadyAddedError')]); + } + + add_podcast_group($user, $this->podcast->id, $this->request->getPost('role')); + + return redirect()->route('contributor-list', [$this->podcast->id]); + } + + public function editView(): string|RedirectResponse + { + helper('form'); + + $roles = setting('AuthGroups.podcastBaseGroups'); + $roleOptions = []; + array_walk( + $roles, + static function (string $role) use (&$roleOptions): array { + $roleOptions[] = [ + 'value' => $role, + 'label' => lang('Auth.podcast_groups.' . $role . '.title'), + ]; + return $roleOptions; + }, + [], + ); + + $contributorGroup = get_podcast_group($this->contributor, $this->podcast->id); + + if ($contributorGroup === null) { + return redirect() + ->back() + ->withInput() + ->with('errors', [lang('Contributor.messages.notAddedError')]); + } + + $data = [ + 'podcast' => $this->podcast, + 'contributor' => $this->contributor, + 'contributorGroup' => $contributorGroup, + 'roleOptions' => $roleOptions, + ]; + + $this->setHtmlHead(lang('Contributor.edit_role', [esc($this->contributor->username)])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => $this->contributor->username, + ]); + return view('contributor/edit', $data); + } + + public function editAction(): RedirectResponse + { + // forbid updating a podcast owner + if ($this->podcast->created_by === $this->contributor->id) { + return redirect() + ->back() + ->with('errors', [lang('Contributor.messages.editOwnerError')]); + } + + $group = $this->request->getPost('role'); + + set_podcast_group($this->contributor, $this->podcast->id, $group); + + cache() + ->delete("podcast#{$this->podcast->id}_contributors"); + + return redirect()->route('contributor-list', [$this->podcast->id])->with( + 'message', + lang('Contributor.messages.editSuccess'), + ); + } + + public function removeView(): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + 'contributor' => $this->contributor, + ]; + + $this->setHtmlHead(lang('Contributor.delete_form.title', [ + 'contributor' => $this->contributor->username, + ])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => $this->contributor->username, + ]); + return view('contributor/remove', $data); + } + + public function removeAction(): RedirectResponse + { + if ($this->podcast->created_by === $this->contributor->id) { + return redirect() + ->back() + ->with('errors', [lang('Contributor.messages.removeOwnerError')]); + } + + $rules = [ + 'understand' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + cache() + ->delete("podcast#{$this->podcast->id}_contributors"); + + // remove contributor from podcast group + $this->contributor->removeGroup(get_podcast_group($this->contributor, $this->podcast->id, false)); + + return redirect() + ->route('contributor-list', [$this->podcast->id]) + ->with( + 'message', + lang('Contributor.messages.removeSuccess', [ + 'username' => $this->contributor->username, + 'podcastTitle' => $this->podcast->title, + ]), + ); + } +} diff --git a/modules/Auth/Controllers/InteractController.php b/modules/Auth/Controllers/InteractController.php new file mode 100644 index 00000000..d8281b62 --- /dev/null +++ b/modules/Auth/Controllers/InteractController.php @@ -0,0 +1,36 @@ + 'required|numeric', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + helper('auth'); + + set_interact_as_actor((int) $validData['actor_id']); + + return redirect()->back(); + } +} diff --git a/modules/Auth/Controllers/LoginController.php b/modules/Auth/Controllers/LoginController.php new file mode 100644 index 00000000..d4d7386e --- /dev/null +++ b/modules/Auth/Controllers/LoginController.php @@ -0,0 +1,26 @@ +to(config('Auth')->loginRedirect()); + } + + return view(setting('Auth.views')['magic-link-set-password']); + } + + public function setPasswordAction(): RedirectResponse + { + $rules = [ + 'new_password' => 'required|strong_password', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $user = auth() + ->user(); + + if ($user instanceof User) { + // set new password to user + $user->password = $validData['new_password']; + + $userModel = auth() + ->getProvider(); + $userModel->save($user); + } + + // remove magic login session to reinstate normal check + if (session('magicLogin')) { + session()->removeTempdata('magicLogin'); + } + + // Success! + return redirect()->to(config('Auth')->loginRedirect()) + ->with('message', lang('MyAccount.messages.passwordChangeSuccess')); + } +} diff --git a/modules/Auth/Controllers/MyAccountController.php b/modules/Auth/Controllers/MyAccountController.php new file mode 100644 index 00000000..844b0112 --- /dev/null +++ b/modules/Auth/Controllers/MyAccountController.php @@ -0,0 +1,82 @@ +setHtmlHead(lang('MyAccount.info')); + return view('my_account/view'); + } + + public function changePassword(): string + { + helper('form'); + + $this->setHtmlHead(lang('MyAccount.changePassword')); + return view('my_account/change_password'); + } + + public function changeAction(): RedirectResponse + { + $rules = [ + 'password' => 'required', + 'new_password' => 'required|strong_password|differs[password]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + // check credentials with the old password if logged in without magic link + $credentials = [ + 'email' => auth() + ->user() + ->email, + 'password' => $validData['password'], + ]; + + $validCreds = auth() + ->check($credentials); + + if (! $validCreds->isOK()) { + return redirect()->back() + ->with('error', lang('MyAccount.messages.wrongPasswordError')); + } + + $user = auth() + ->user(); + + if ($user instanceof User) { + // set new password to user + $user->password = $validData['new_password']; + + $userModel = auth() + ->getProvider(); + $userModel->save($user); + } + + // Success! + return redirect() + ->back() + ->with('message', lang('MyAccount.messages.passwordChangeSuccess')); + } +} diff --git a/modules/Auth/Controllers/RegisterController.php b/modules/Auth/Controllers/RegisterController.php new file mode 100644 index 00000000..4a093f95 --- /dev/null +++ b/modules/Auth/Controllers/RegisterController.php @@ -0,0 +1,29 @@ +{$method}(); + } + + if (($this->user = new UserModel()->find($params[0])) instanceof User) { + return $this->{$method}(); + } + + throw PageNotFoundException::forPageNotFound(); + } + + public function list(): string + { + $data = [ + 'users' => new UserModel() + ->findAll(), + ]; + + $this->setHtmlHead(lang('User.all_users')); + return view('user/list', $data); + } + + public function view(): string + { + $data = [ + 'user' => $this->user, + ]; + + $this->setHtmlHead(lang('User.view', [ + 'username' => esc($this->user->username), + ])); + replace_breadcrumb_params([ + 0 => $this->user->username, + ]); + return view('user/view', $data); + } + + public function createView(): string + { + helper('form'); + + $roles = setting('AuthGroups.instanceGroups'); + $roleOptions = []; + array_walk( + $roles, + static function (array $role, $key) use (&$roleOptions): array { + $roleOptions[] = [ + 'value' => $key, + 'label' => $role['title'], + ]; + return $roleOptions; + }, + [], + ); + + $data = [ + 'roleOptions' => $roleOptions, + ]; + + $this->setHtmlHead(lang('User.create')); + return view('user/create', $data); + } + + /** + * Create the user with the provided username and email. The password is set as a random string and a magic link is + * sent to the user to allow them setting their password. + */ + public function createAction(): RedirectResponse + { + helper(['text', 'email']); + + $db = db_connect(); + $db->transStart(); + + $userModel = new UserModel(); + + // Save the user + $email = $this->request->getPost('email'); + $user = new User([ + 'username' => $this->request->getPost('username'), + 'email' => $email, + // set a random password + // user will be prompted to change it on first magic link login. + 'password' => random_string('alnum', 32), + ]); + try { + $userModel->save($user); + } catch (ValidationException) { + return redirect()->back() + ->withInput() + ->with('errors', $userModel->errors()); + } + + $user = $userModel->findById($userModel->getInsertID()); + $user->addGroup($this->request->getPost('role')); + + // **** SEND WELCOME LINK FOR FIRST LOGIN **** + + $identityModel = model('UserIdentityModel'); + + // Delete any previous magic-link identities + $identityModel->deleteIdentitiesByType($user, Session::ID_TYPE_MAGIC_LINK); + + // Generate the code and save it as an identity + $token = random_string('crypto', 20); + + $identityModel->insert([ + 'user_id' => $user->id, + 'type' => Session::ID_TYPE_MAGIC_LINK, + 'secret' => $token, + 'expires' => Time::now()->addSeconds(setting('Auth.welcomeLinkLifetime'))->format('Y-m-d H:i:s'), + ]); + + // Send the user an email with the code + $email = emailer() + ->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? ''); + $email->setTo($user->email); + $email->setSubject(lang('Auth.welcomeSubject', [ + 'siteName' => setting('App.siteName'), + ])); + $email->setMessage(view(setting('Auth.views')['welcome-email'], [ + 'token' => $token, + ], [ + 'theme' => 'auth', + ])); + + if (! $email->send(false)) { + log_message('error', $email->printDebugger(['headers'])); + + return redirect()->back() + ->with('error', lang('Auth.unableSendEmailToUser', [$user->email])); + } + + // Clear the email + $email->clear(); + + $db->transComplete(); + + // Success! + return redirect() + ->route('user-list') + ->with('message', lang('User.messages.createSuccess', [ + 'username' => $user->username, + ])); + } + + public function editView(): string + { + helper('form'); + + $roles = setting('AuthGroups.instanceGroups'); + $roleOptions = []; + array_walk( + $roles, + static function (array $role, $key) use (&$roleOptions): array { + $roleOptions[] = [ + 'value' => $key, + 'label' => $role['title'], + ]; + return $roleOptions; + }, + [], + ); + + $data = [ + 'user' => $this->user, + 'roleOptions' => $roleOptions, + ]; + + $this->setHtmlHead(lang('User.edit_role', [ + 'username' => esc($this->user->username), + ])); + replace_breadcrumb_params([ + 0 => $this->user->username, + ]); + return view('user/edit', $data); + } + + public function editAction(): RedirectResponse + { + // The instance owner is a superadmin and the only user that cannot be demoted. + if ((bool) $this->user->is_owner) { + return redirect() + ->back() + ->with('errors', [ + lang('User.messages.editOwnerError', [ + 'username' => $this->user->username, + ]), + ]); + } + + $group = $this->request->getPost('role'); + + set_instance_group($this->user, $group); + + // Success! + return redirect() + ->route('user-list') + ->with('message', lang('User.messages.roleEditSuccess', [ + 'username' => $this->user->username, + ])); + } + + public function deleteView(): string + { + helper(['form']); + + $data = [ + 'user' => $this->user, + ]; + + $this->setHtmlHead(lang('User.delete_form.title', [ + 'user' => $this->user->username, + ])); + replace_breadcrumb_params([ + 0 => $this->user->username, + ]); + return view('user/delete', $data); + } + + public function deleteAction(): RedirectResponse + { + // You cannot delete the instance owner. + if ((bool) $this->user->is_owner) { + return redirect() + ->back() + ->with('errors', [ + lang('User.messages.deleteOwnerError', [ + 'username' => $this->user->username, + ]), + ]); + } + + // You cannot delete a superadmin + // superadmin has to be demoted before being deleted + if ($this->user->inGroup(setting('AuthGroups.mostPowerfulPodcastGroup'))) { + return redirect() + ->back() + ->with('errors', [ + lang('User.messages.deleteSuperAdminError', [ + 'username' => $this->user->username, + ]), + ]); + } + + $rules = [ + 'understand' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + new UserModel() + ->delete($this->user->id, true); + + return redirect() + ->route('user-list') + ->with('message', lang('User.messages.deleteSuccess', [ + 'username' => $this->user->username, + ])); + } +} diff --git a/modules/Auth/Database/Migrations/2020-12-29-100000_add_is_owner_to_users.php b/modules/Auth/Database/Migrations/2020-12-29-100000_add_is_owner_to_users.php new file mode 100644 index 00000000..7f0badee --- /dev/null +++ b/modules/Auth/Database/Migrations/2020-12-29-100000_add_is_owner_to_users.php @@ -0,0 +1,32 @@ + [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + 'null' => false, + ], + ]; + + $this->forge->addColumn('users', $fields); + } + + #[Override] + public function down(): void + { + $fields = ['is_owner']; + $this->forge->dropColumn('users', $fields); + } +} diff --git a/modules/Auth/Filters/.gitkeep b/modules/Auth/Filters/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/modules/Auth/Filters/PermissionFilter.php b/modules/Auth/Filters/PermissionFilter.php new file mode 100644 index 00000000..982e9f64 --- /dev/null +++ b/modules/Auth/Filters/PermissionFilter.php @@ -0,0 +1,108 @@ +loggedIn()) { + return redirect()->route('login'); + } + + if ($this->isAuthorized($arguments)) { + return null; + } + + throw new RuntimeException(lang('Auth.notEnoughPrivilege'), 403); + } + + /** + * @param string[]|null $arguments + * + * @return ResponseInterface|null + */ + #[Override] + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + return null; + } + + /** + * Ensures the user is logged in and has one or more + * of the permissions as specified in the filter. + * + * @param string[] $arguments + */ + protected function isAuthorized(array $arguments): bool + { + $result = true; + + foreach ($arguments as $permission) { + // is permission specific to a podcast? + if (str_contains($permission, '$')) { + $router = service('router'); + $routerParams = $router->params(); + + if (! preg_match('/\$(\d+)\./', $permission, $match)) { + throw new RuntimeException(sprintf( + 'Could not get podcast identifier from permission %s', + $permission, + ), 1); + } + + $paramKey = ((int) $match[1]) - 1; + if (! array_key_exists($paramKey, $routerParams)) { + throw new RuntimeException(sprintf('Router param does not exist at key %s', $match[1]), 1); + } + + $podcastParam = $routerParams[$paramKey]; + + // get podcast id + $podcastId = null; + if (is_numeric($podcastParam)) { + $podcastId = (int) $podcastParam; + } else { + $podcast = new PodcastModel() + ->getPodcastByHandle($podcastParam); + if ($podcast instanceof Podcast) { + $podcastId = $podcast->id; + } + } + + if ($podcastId !== null) { + $permission = str_replace('$' . $match[1], '#' . $podcastId, $permission); + } + } + + $result = $result && auth() + ->user() + ->can($permission); + } + + return $result; + } +} diff --git a/modules/Auth/Helpers/auth_helper.php b/modules/Auth/Helpers/auth_helper.php new file mode 100644 index 00000000..36b6a075 --- /dev/null +++ b/modules/Auth/Helpers/auth_helper.php @@ -0,0 +1,305 @@ +setAuthenticator($alias); + } +} + +if (! function_exists('set_interact_as_actor')) { + /** + * Sets the actor id of which the user is acting as + */ + function set_interact_as_actor(int $actorId): void + { + if (auth()->loggedIn()) { + session() + ->set('interact_as_actor_id', $actorId); + } + } +} + +if (! function_exists('remove_interact_as_actor')) { + /** + * Removes the actor id of which the user is acting as + */ + function remove_interact_as_actor(): void + { + session()->remove('interact_as_actor_id'); + } +} + +if (! function_exists('interact_as_actor_id')) { + /** + * Sets the podcast id of which the user is acting as + */ + function interact_as_actor_id(): ?int + { + return session()->get('interact_as_actor_id'); + } +} + +if (! function_exists('interact_as_actor')) { + /** + * Get the actor the user is currently interacting as + */ + function interact_as_actor(): ?Actor + { + if (! auth()->loggedIn()) { + return null; + } + + $session = session(); + if (! $session->has('interact_as_actor_id')) { + return null; + } + + return model(ActorModel::class, false)->getActorById($session->get('interact_as_actor_id')); + } +} + +if (! function_exists('can_user_interact')) { + function can_user_interact(): bool + { + return (bool) interact_as_actor(); + } +} + +if (! function_exists('add_podcast_group')) { + function add_podcast_group(User $user, int $podcastId, string $group): User + { + $podcastGroup = 'podcast#' . $podcastId . '-' . $group; + + return $user->addGroup($podcastGroup); + } +} + +if (! function_exists('get_instance_group')) { + function get_instance_group(User $user): ?string + { + $instanceGroups = array_filter( + $user->getGroups() ?? [], + static fn ($group): bool => ! str_starts_with((string) $group, 'podcast#'), + ); + + if ($instanceGroups === []) { + return null; + } + + $instanceGroup = array_shift($instanceGroups); + + // Verify that a user belongs to one group only! + if ($instanceGroups !== []) { + // remove any other group the user belongs to + $user->removeGroup(...$instanceGroups); + } + + return $instanceGroup; + } +} + +if (! function_exists('set_instance_group')) { + function set_instance_group(User $user, string $group): User + { + // remove old instance group + if (get_instance_group($user)) { + $user->removeGroup(get_instance_group($user)); + } + + // set new group + return $user->addGroup($group); + } +} + +if (! function_exists('get_podcast_group')) { + function get_podcast_group(User $user, int $podcastId, bool $removePrefix = true): ?string + { + $podcastGroups = array_filter( + $user->getGroups() ?? [], + static fn ($group): bool => str_starts_with((string) $group, "podcast#{$podcastId}-"), + ); + + if ($podcastGroups === []) { + return null; + } + + $podcastGroup = array_shift($podcastGroups); + + // Verify that a user belongs to one group only! + if ($podcastGroups !== []) { + // remove any other group the user belongs to + $user->removeGroup(...$podcastGroups); + } + + if ($removePrefix) { + // strip the `podcast#{id}-` prefix when returning group + return substr((string) $podcastGroup, strlen('podcast#' . $podcastId . '-')); + } + + return $podcastGroup; + } +} + +if (! function_exists('set_podcast_group')) { + function set_podcast_group(User $user, int $podcastId, string $group): User + { + // remove old instance group + $user->removeGroup("podcast#{$podcastId}-" . get_podcast_group($user, $podcastId)); + + // set new group + return add_podcast_group($user, $podcastId, $group); + } +} + +if (! function_exists('get_podcast_groups')) { + /** + * @return string[] + */ + function get_user_podcast_ids(User $user): array + { + $podcastGroups = array_filter( + $user->getGroups() ?? [], + static fn ($group): bool => str_starts_with((string) $group, 'podcast#'), + ); + + $userPodcastIds = []; + // extract all podcast ids from groups + foreach ($podcastGroups as $podcastGroup) { + // extract podcast id from group and add it to the list of ids + preg_match('~podcast#(\d+)-[a-z]+~', (string) $podcastGroup, $matches); + $userPodcastIds[] = $matches[1]; + } + + return $userPodcastIds; + } +} + +if (! function_exists('can_podcast')) { + function can_podcast(User $user, int $podcastId, string $permission): bool + { + return $user->can('podcast#' . $podcastId . '.' . $permission); + } +} + +if (! function_exists('get_user_podcasts')) { + /** + * Returns the podcasts the user is contributing to + * + * @return Podcast[] + */ + function get_user_podcasts(User $user): array + { + return new PodcastModel() + ->getUserPodcasts($user->id, get_user_podcast_ids($user)); + } +} + +if (! function_exists('get_podcasts_user_can_interact_with')) { + /** + * @return Podcast[] + */ + function get_podcasts_user_can_interact_with(User $user): array + { + $userPodcasts = new PodcastModel() + ->getUserPodcasts($user->id, get_user_podcast_ids($user)); + + $hasInteractAsPrivilege = interact_as_actor_id() === null; + + if ($userPodcasts === []) { + if ($hasInteractAsPrivilege) { + remove_interact_as_actor(); + } + + return []; + } + + $isInteractAsPrivilegeLost = true; + $podcastsUserCanInteractWith = []; + foreach ($userPodcasts as $userPodcast) { + if (can_podcast($user, $userPodcast->id, 'interact-as')) { + if (interact_as_actor_id() === $userPodcast->actor_id) { + $isInteractAsPrivilegeLost = false; + } + + $podcastsUserCanInteractWith[] = $userPodcast; + } + } + + if ($podcastsUserCanInteractWith === []) { + if (interact_as_actor_id() !== null) { + remove_interact_as_actor(); + } + + return []; + } + + // check if user has lost the interact as privilege for current podcast actor. + // --> Remove interact as if there's no podcast actor to interact as + // or set the first podcast actor the user can interact as + if ($isInteractAsPrivilegeLost) { + set_interact_as_actor($podcastsUserCanInteractWith[0]->actor_id); + } + + return $podcastsUserCanInteractWith; + } +} + +if (! function_exists('get_actor_ids_with_unread_notifications')) { + /** + * Returns the ids of the user's actors that have unread notifications + * + * @return int[] + */ + function get_actor_ids_with_unread_notifications(User $user): array + { + if (($userPodcasts = get_user_podcasts($user)) === []) { + return []; + } + + $unreadNotifications = new NotificationModel() + ->whereIn('target_actor_id', array_column($userPodcasts, 'actor_id')) + ->where('read_at') + ->findAll(); + + return array_column($unreadNotifications, 'target_actor_id'); + } +} + +if (! function_exists('get_group_title')) { + /** + * @return array<'title'|'description', string> + */ + function get_group_info(string $group, ?int $podcastId = null): array + { + if ($podcastId === null) { + return setting('AuthGroups.instanceGroups')[$group]; + } + + return setting('AuthGroups.podcastGroups')[$group]; + } +} diff --git a/modules/Auth/Language/ar/Auth.php b/modules/Auth/Language/ar/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/ar/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/ar/Contributor.php b/modules/Auth/Language/ar/Contributor.php new file mode 100644 index 00000000..4731c799 --- /dev/null +++ b/modules/Auth/Language/ar/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'إضافة مساهم', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'تعديل', + 'remove' => 'إزالة', + 'list' => [ + 'username' => 'اسم المستخدم', + 'role' => 'الدور', + ], + 'form' => [ + 'user' => 'مستخدم', + 'user_placeholder' => 'اختر مستخدمًا…', + 'role' => 'الدور', + 'role_placeholder' => 'اختر دوره…', + 'submit_add' => 'إضافة مساهم', + 'submit_edit' => 'حدّث الدور', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "لا يمكنك إزالة صاحب البودكاست!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/ar/MyAccount.php b/modules/Auth/Language/ar/MyAccount.php new file mode 100644 index 00000000..6f81940b --- /dev/null +++ b/modules/Auth/Language/ar/MyAccount.php @@ -0,0 +1,18 @@ + 'معلومات حسابي', + 'changePassword' => 'تغيير كلمتي السرية', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/ar/User.php b/modules/Auth/Language/ar/User.php new file mode 100644 index 00000000..39f78c2e --- /dev/null +++ b/modules/Auth/Language/ar/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'احذف', + 'create' => 'مستخدم جديد', + 'view' => "{username}'s info", + 'all_users' => 'كافة المستخدمين', + 'list' => [ + 'user' => 'مستخدم', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'البريد الإلكتروني', + 'username' => 'اسم المستخدم', + 'password' => 'كلمة المرور', + 'new_password' => 'كلمة المرور الجديدة', + 'role' => 'Role', + 'roles' => 'الأدوار', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'حفظ', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/br/Auth.php b/modules/Auth/Language/br/Auth.php new file mode 100644 index 00000000..9730b849 --- /dev/null +++ b/modules/Auth/Language/br/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Perc\'henn·ez an istañs', + 'description' => 'Perc\'henn·ez Castopod.', + ], + 'superadmin' => [ + 'title' => 'Dreistmerour·ez', + 'description' => 'Ur c\'hontroll klok en deus war Castopod.', + ], + 'manager' => [ + 'title' => 'Merour·ez', + 'description' => 'Merañ a ra endalc\'had Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podkaster', + 'description' => 'Implijerien·ezed kustum Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Gallout a ra gwelet taolenn-stur Castopod.', + 'admin.settings' => 'Gallout a ra gwelet arventennoù Castopod.', + 'users.manage' => 'Gallout a ra ober war-dro implijerien·ezed Castopod.', + 'persons.manage' => 'Gallout a ra merañ an emellerien·ezed.', + 'pages.manage' => 'Gallout a ra merañ ar pajennoù.', + 'podcasts.view' => 'Gallout a ra gwelet an holl bodkastoù.', + 'podcasts.create' => 'Gallout a ra krouiñ podkastoù nevez.', + 'podcasts.import' => 'Gallout a ra enporzhiañ podkastoù.', + 'fediverse.manage-blocks' => 'Gallout a ra mirout aktourien·ezed pe domanioù ar Fediverse ouzh kaout darempredoù gant Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Perc\'henn·ez ar podkast', + 'description' => 'Perc\'henn·ez ar podkast.', + ], + 'admin' => [ + 'title' => 'Merour·ez', + 'description' => 'Ur c\'hontroll klok en deus war ar podkast #{id}.', + ], + 'editor' => [ + 'title' => 'Embanner', + 'description' => 'Merañ a ra endalc\'had hag embannadurioù ar podkast #{id}.', + ], + 'author' => [ + 'title' => 'Aozer·ez', + 'description' => 'Merañ a ra endalc\'had ar podkast #{id} met ne c\'hall ket embann anezho.', + ], + 'guest' => [ + 'title' => 'Kouviad·ez', + 'description' => 'Perzhiad·ez eus ar podkast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Gallout a ra gwelet taolenn-stur ha muzulioù heklev ar podkast #{id}.', + 'edit' => 'Gallout a ra kemmañ ar podkast #{id}.', + 'delete' => 'Gallout a ra lemel ar podkast #{id}.', + 'manage-import' => 'Gallout a ra sinkronekaat ar podkast enporzhiet #{id}.', + 'manage-persons' => 'Gallout a ra merañ koumanantoù ar podkast #{id}.', + 'manage-subscriptions' => 'Gallout a ra merañ koumanantoù ar podkast #{id}.', + 'manage-contributors' => 'Gallout a ra merañ perzhidi ha perzhiadezed ar podkast #{id}.', + 'manage-platforms' => 'Gallout a ra ouzhpennañ pe lemel liammoù etrezek savennoù diavaez evit ar podkast #{id}.', + 'manage-publications' => 'Gallout a ra embann ar podkast #{id}.', + 'manage-notifications' => 'Gallout a ra gwelet kemennoù ar podkast #{id} ha lakaat anezho evel lennet.', + 'interact-as' => 'Gallout a ra ober traoù gant identelezh ar podkast #{id}: ouzhpennañ ur gemennadenn d\'ar re garetañ, rannañ anezhi pe respont dezhi.', + 'episodes' => [ + 'view' => 'Gallout a ra gwelet taolennoù-stur ha muzulioù heklev rannoù ar podkast #{id}.', + 'create' => 'Gallout a ra krouiñ rannoù evit podkast #{id}.', + 'edit' => 'Gallout a ra kemmañ rannoù ar podkast #{id}.', + 'delete' => 'Gallout a ra lemel rannoù ar podkast #{id}.', + 'manage-persons' => 'Gallout a ra merañ emellerien·ezed ar podkast #{id}.', + 'manage-clips' => 'Gallout a ra merañ klipoù video pe tennadoù son ar podkast #{id}.', + 'manage-publications' => 'Gallout a ra embann pe diembann rannoù ha kemennadennoù ar podkast #{id}.', + 'manage-comments' => 'Gallout a ra krouiñ/lemel evezhiadennoù evit rannoù ar podkast #{id}.', + ], + ], + + // missing keys + 'code' => 'Ho kod 6 sifr dezhañ', + + 'set_password' => 'Skrivit ho ker-tremen', + + // Welcome email + 'welcomeSubject' => 'Pedet oc\'h bet da vont war {siteName}', + 'emailWelcomeMailBody' => 'Krouet ez eus bet ur gont deoc\'h war {domain}. Klikit war al liamm amañ-dindan evit choaz ur ger-tremen. Bev e vo al liamm betek {numberOfHours} eur goude m\'eo bet kaset ar postel-mañ.', +]; diff --git a/modules/Auth/Language/br/Contributor.php b/modules/Auth/Language/br/Contributor.php new file mode 100644 index 00000000..bffc79e0 --- /dev/null +++ b/modules/Auth/Language/br/Contributor.php @@ -0,0 +1,47 @@ + 'Perzhidi ha perzhiadezed ar podkast', + 'view' => "Perzh {username} e {podcastTitle}", + 'add' => 'Ouzhpennañ ur perzhiad pe ur berzhiadez', + 'add_contributor' => 'Ouzhpennañ ur perzhiad pe ur berzhiadez da {0}', + 'edit_role' => 'Nevesaat roll {0}', + 'edit' => 'Kemmañ', + 'remove' => 'Lemel', + 'list' => [ + 'username' => 'Anv implijer·ez', + 'role' => 'Roll', + ], + 'form' => [ + 'user' => 'Implijer·ez', + 'user_placeholder' => 'Dibabit un implijer·ez…', + 'role' => 'Roll', + 'role_placeholder' => 'Dibabit e·he roll…', + 'submit_add' => 'Ouzhpennañ ur perzhiad pe ur berzhiadez', + 'submit_edit' => 'Nevesaat ar roll', + ], + 'delete_form' => [ + 'title' => 'Dilemel {contributor}', + 'disclaimer' => + 'Emaoc\'h o vont da lemel {contributor} eus ar berzhidi/perzhiadezed. Ne c\'hallo ket gwelet "{podcastTitle}" ken.', + 'understand' => 'Komprenet em eus. Fellout a ra din lemel {contributor} eus "{podcastTitle}"', + 'submit' => 'Lemel', + ], + 'messages' => [ + 'editSuccess' => 'Cheñchet eo bet ar roll gant berzh!', + 'editOwnerError' => "Ne c'hellit ket kemmañ perc'henn·ez ar podkast!", + 'removeOwnerError' => "Ne c'hellit ket lemel perc'henn ar podkast!", + 'removeSuccess' => + 'Lamet ho peus {username} diouzh {podcastTitle} gant berzh', + 'alreadyAddedError' => + "Ar perzhiad pe ar berzhiadez emaoc'h o klask ouzhpennañ zo bet ouzhpennet dija!", + ], +]; diff --git a/modules/Auth/Language/br/MyAccount.php b/modules/Auth/Language/br/MyAccount.php new file mode 100644 index 00000000..df980892 --- /dev/null +++ b/modules/Auth/Language/br/MyAccount.php @@ -0,0 +1,18 @@ + 'Titouroù diwar-benn ma c\'hont', + 'changePassword' => 'Kemmañ ma ger-tremen', + 'messages' => [ + 'wrongPasswordError' => "N'eo ket talvoudek ar ger-tremen ho peus skrivet. Klaskit en-dro.", + 'passwordChangeSuccess' => 'Kemmet eo bet ar ger-tremen gant berzh!', + ], +]; diff --git a/modules/Auth/Language/br/User.php b/modules/Auth/Language/br/User.php new file mode 100644 index 00000000..accd5af9 --- /dev/null +++ b/modules/Auth/Language/br/User.php @@ -0,0 +1,60 @@ + "Kemmañ roll {username}", + 'ban' => 'Stankañ', + 'unban' => 'Distankañ', + 'delete' => 'Dilemel', + 'create' => 'Krouiñ un implijer·ez', + 'view' => "Titouroù diwar-benn {username}", + 'all_users' => 'An holl implijerien·ezed', + 'list' => [ + 'user' => 'Implijer·ez', + 'role' => 'Roll', + 'banned' => 'Stanket?', + ], + 'form' => [ + 'email' => 'Postel', + 'username' => 'Anv implijer·ez', + 'password' => 'Ger-tremen', + 'new_password' => 'Ger-tremen nevez', + 'role' => 'Roll', + 'roles' => 'Rolloù', + 'permissions' => 'Aotreoù', + 'submit_create' => 'Krouiñ an implijer·ez', + 'submit_edit' => 'Enrollañ', + 'submit_password_change' => 'Kemm!', + ], + 'delete_form' => [ + 'title' => 'Dilemel {user}', + 'disclaimer' => + "Emaoc'h o vont da lemel {user} da vat. Ne c'hallo ket gwelet an daolenn-stur ken.", + 'understand' => 'Komprenet em eus. Fellout a ra din lemel {user} da vat', + 'submit' => 'Dilemel', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "Rolloù {username} zo bet nevesaet gant berzh.", + 'banSuccess' => 'Stanket eo bet {username}.', + 'unbanSuccess' => 'Distanket eo bet {username}.', + 'editOwnerError' => + '{username} eo perc\'henn·ez an istañs. Ne c\'hallit ket kemmañ e rolloù…', + 'banSuperAdminError' => + 'Dreistmerour·ez eo {username}, n\'haller ket stankañ un dreistmerour·ez ken aes-se…', + 'deleteOwnerError' => + '{username} eo perc\'henn·ez an istañs. N\'haller ket lemel ar perc\'henn·ez ken aes-se…', + 'deleteSuperAdminError' => + 'Dreistmerour·ez eo {username}, n\'haller ket lemel un dreistmerour·ez ken aes-se…', + 'deleteSuccess' => 'Dilamet eo bet {username}.', + ], +]; diff --git a/modules/Auth/Language/ca/Auth.php b/modules/Auth/Language/ca/Auth.php new file mode 100644 index 00000000..3478f697 --- /dev/null +++ b/modules/Auth/Language/ca/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Propietari de la instància', + 'description' => 'Propietari del Castopod.', + ], + 'superadmin' => [ + 'title' => 'Super administrador', + 'description' => 'Té control complet sobre Castopod.', + ], + 'manager' => [ + 'title' => 'Administrador', + 'description' => 'Administra el contingut de Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Usos generals de Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Pot accedir a l\'àrea d\'administració de Castopod.', + 'admin.settings' => 'Pot accedir a la configuració de Castopod.', + 'users.manage' => 'Pot administrar els usuaris de Castopod.', + 'persons.manage' => 'Pot administrar persones.', + 'pages.manage' => 'Pot administrar pàgines.', + 'podcasts.view' => 'Pot veure els pòdcasts.', + 'podcasts.create' => 'Pot crear nous pòdcasts.', + 'podcasts.import' => 'Pot importar pòdcasts.', + 'fediverse.manage-blocks' => 'Pot evitar que actors/dominis del fedivers interactuen amb Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Propietari del pòdcast', + 'description' => 'El propietari del pòdcast.', + ], + 'admin' => [ + 'title' => 'Administrador', + 'description' => 'Té control complet del pòdcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Administra els continguts i la publicació del pòdcast #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Administra el contingut del podcast #{id} però no el pot publicar.', + ], + 'guest' => [ + 'title' => 'Convidat', + 'description' => 'Col·laborador general del podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Pot veure el tauler i les estadístiques del podcast #{id}.', + 'edit' => 'Pot editar el podcast #{id}.', + 'delete' => 'Pot suprimir el podcast #{id}.', + 'manage-import' => 'Pot sincronitzar el podcast importat #{id}.', + 'manage-persons' => 'Pot gestionar les subscripcions del podcast #{id}.', + 'manage-subscriptions' => 'Pot gestionar les subscripcions del podcast #{id}.', + 'manage-contributors' => 'Pot gestionar els col·laboradors del podcast #{id}.', + 'manage-platforms' => 'Pot establir/eliminar enllaços de plataforma del podcast #{id}.', + 'manage-publications' => 'Pot publicar el podcast #{id}.', + 'manage-notifications' => 'Pot veure i marcar les notificacions com a llegides per al podcast #{id}.', + 'interact-as' => 'Pot interactuar en nom del podcast #{id} per marcar les publicacions com a preferides, compartir-les o respondre-hi.', + 'episodes' => [ + 'view' => 'Pot veure taulers i estadístiques dels episodis del podcast #{id}.', + 'create' => 'Pot crear episodis per al podcast #{id}.', + 'edit' => 'Pot editar episodis del podcast #{id}.', + 'delete' => 'Pot suprimir episodis del podcast #{id}.', + 'manage-persons' => 'Pot gestionar persones d\'episodi del podcast #{id}.', + 'manage-clips' => 'Pot gestionar clips de vídeo o fragments de so del pòdcast #{id}.', + 'manage-publications' => 'Pot publicar/anul·lar la publicació d\'episodis i publicacions del pòdcast #{id}.', + 'manage-comments' => 'Pot crear/eliminar comentaris d\'episodi del pòdcast #{id}.', + ], + ], + + // missing keys + 'code' => 'El teu codi de 6 dígits', + + 'set_password' => 'Estableix la teva contrasenya', + + // Welcome email + 'welcomeSubject' => 'Has estat convidat a {siteName}', + 'emailWelcomeMailBody' => 'S\'ha creat un compte per a tu a {domain}, fes clic a l\'enllaç d\'inici de sessió següent per configurar la teva contrasenya. L\'enllaç és vàlid durant {numberOfHours} hores després de l\'hora d\'enviament d\'aquest correu electrònic.', +]; diff --git a/modules/Auth/Language/ca/Contributor.php b/modules/Auth/Language/ca/Contributor.php new file mode 100644 index 00000000..4105f38e --- /dev/null +++ b/modules/Auth/Language/ca/Contributor.php @@ -0,0 +1,47 @@ + 'Col·laboradors del podcast', + 'view' => "Aportació de {username} a {podcastTitle}", + 'add' => 'Afegir un col·laborador', + 'add_contributor' => 'Afegir un col·laborador de {0}', + 'edit_role' => 'Actualitzar el rol de {0}', + 'edit' => 'Editar', + 'remove' => 'Eliminar', + 'list' => [ + 'username' => 'Nom de l\'usuari', + 'role' => 'Rol', + ], + 'form' => [ + 'user' => 'Usuari', + 'user_placeholder' => 'Seleccionar un usuari…', + 'role' => 'Rol', + 'role_placeholder' => 'Seleccionar el seu rol…', + 'submit_add' => 'Afegir un col·laborador', + 'submit_edit' => 'Actualitzar el rol', + ], + 'delete_form' => [ + 'title' => 'Suprimeix {contributor}', + 'disclaimer' => + 'Esteu a punt d\'eliminar {contributor} dels col·laboradors. Ja no podrà accedir a "{podcastTitle}".', + 'understand' => 'Entenc, vull eliminar {contributor} de "{podcastTitle}"', + 'submit' => 'Suprimeix', + ], + 'messages' => [ + 'editSuccess' => 'El rol ha canviat correctament!', + 'editOwnerError' => "No pots editar el propietari del podcast!", + 'removeOwnerError' => "No podeu eliminar al propietari del podcast!", + 'removeSuccess' => + 'S\'ha eliminat a {username} de {podcastTitle}', + 'alreadyAddedError' => + "El col·laborador que esteu intentant afegir ja ha estat afegit!", + ], +]; diff --git a/modules/Auth/Language/ca/MyAccount.php b/modules/Auth/Language/ca/MyAccount.php new file mode 100644 index 00000000..3522f769 --- /dev/null +++ b/modules/Auth/Language/ca/MyAccount.php @@ -0,0 +1,18 @@ + 'Informació del meu compte', + 'changePassword' => 'Canviar la meva contrasenya', + 'messages' => [ + 'wrongPasswordError' => "Heu introduït una contrasenya incorrecta, torneu a provar.", + 'passwordChangeSuccess' => 'S\'ha canviat correctament la contrasenya.', + ], +]; diff --git a/modules/Auth/Language/ca/User.php b/modules/Auth/Language/ca/User.php new file mode 100644 index 00000000..c269cfa4 --- /dev/null +++ b/modules/Auth/Language/ca/User.php @@ -0,0 +1,60 @@ + "Editeu el rol de {username}", + 'ban' => 'Bandejar', + 'unban' => 'Re-admetre', + 'delete' => 'Eliminar', + 'create' => 'Nou usuari', + 'view' => "Informació de {username}", + 'all_users' => 'Tots els usuaris', + 'list' => [ + 'user' => 'Usuari', + 'role' => 'Rol', + 'banned' => 'Bandejat?', + ], + 'form' => [ + 'email' => 'Correu electrònic', + 'username' => 'Nom de l\'usuari', + 'password' => 'Contrasenya', + 'new_password' => 'Nova contrasenya', + 'role' => 'Rol', + 'roles' => 'Rols', + 'permissions' => 'Permisos', + 'submit_create' => 'Crea un usuari', + 'submit_edit' => 'Desar', + 'submit_password_change' => 'Canviat!', + ], + 'delete_form' => [ + 'title' => 'Suprimeix {user}', + 'disclaimer' => + "Esteu a punt de suprimir {user} permanentment. Ja no podrà accedir a l'àrea d'administració.", + 'understand' => 'Entenc, vull suprimir {user} permanentment', + 'submit' => 'Suprimeix', + ], + 'messages' => [ + 'createSuccess' => + 'S\'ha creat l\'usuari! Es demanarà a {username} un restabliment de la contrasenya durant la primera autenticació.', + 'roleEditSuccess' => + "S'han actualitzat correctament els rols de {username}.", + 'banSuccess' => '{username} ha estat bandejat.', + 'unbanSuccess' => '{username} ha estat desbandejat.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} és un superadministrador, hom simplement no bandeja a un superadministrador...', + 'deleteOwnerError' => + '{username} és el propietari de la instància, un no pot suprimir senzillament el propietari…', + 'deleteSuperAdminError' => + '{username} és un superadministrador, hom simplement no elimina a un superadministrador...', + 'deleteSuccess' => '{username} ha estat eliminat.', + ], +]; diff --git a/modules/Auth/Language/da/Auth.php b/modules/Auth/Language/da/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/da/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/da/Contributor.php b/modules/Auth/Language/da/Contributor.php new file mode 100644 index 00000000..f2685498 --- /dev/null +++ b/modules/Auth/Language/da/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast bidragsydere', + 'view' => "{username}s bidrag til {podcastTitle}", + 'add' => 'Tilføj bidragyder', + 'add_contributor' => 'Tilføj bidragyder til {0}', + 'edit_role' => 'Opdatér rolle for {0}', + 'edit' => 'Redigér', + 'remove' => 'Fjern', + 'list' => [ + 'username' => 'Brugernavn', + 'role' => 'Rolle', + ], + 'form' => [ + 'user' => 'Bruger', + 'user_placeholder' => 'Vælg en bruger…', + 'role' => 'Rolle', + 'role_placeholder' => 'Vælg dens rolle…', + 'submit_add' => 'Tilføj bidragyder', + 'submit_edit' => 'Opdatér rolle', + ], + 'delete_form' => [ + 'title' => 'Fjern {contributor}', + 'disclaimer' => + 'Du er ved at fjerne {contributor} fra bidragydere. De vil ikke længere kunne få adgang til "{podcastTitle}".', + 'understand' => 'Jeg forstår, jeg vil fjerne {contributor} fra "{podcastTitle}"', + 'submit' => 'Fjern', + ], + 'messages' => [ + 'editSuccess' => 'Rolle ændret!', + 'editOwnerError' => "Du kan ikke redigere podcast-ejeren!", + 'removeOwnerError' => "Du kan ikke fjerne podcast-ejeren!", + 'removeSuccess' => + 'Du har fjernet {username} fra {podcastTitle}', + 'alreadyAddedError' => + "Den bidragsyder, du forsøger at tilføje, er allerede blevet tilføjet!", + ], +]; diff --git a/modules/Auth/Language/da/MyAccount.php b/modules/Auth/Language/da/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/da/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/da/User.php b/modules/Auth/Language/da/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/da/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/de/Auth.php b/modules/Auth/Language/de/Auth.php new file mode 100644 index 00000000..e35619ca --- /dev/null +++ b/modules/Auth/Language/de/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instanzbesitzer', + 'description' => 'Der Castopod-Besitzer.', + ], + 'superadmin' => [ + 'title' => 'Super-Administrator', + 'description' => 'Hat die vollständige Kontrolle über Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Verwaltet Castopods Inhalte.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Allgemeine Benutzer von Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Kann auf den Admin-Bereich von Castopod zugreifen.', + 'admin.settings' => 'Kann auf die Einstellungen von Castopod zugreifen.', + 'users.manage' => 'Kann Castopod-Benutzer verwalten.', + 'persons.manage' => 'Kann Mitwirkende verwalten.', + 'pages.manage' => 'Kann Seiten verwalten.', + 'podcasts.view' => 'Kann alle Podcasts einsehen.', + 'podcasts.create' => 'Kann neue Podcasts erstellen.', + 'podcasts.import' => 'Kann Podcasts importieren.', + 'fediverse.manage-blocks' => 'Kann föderierte Nutzer/Domains davon abhalten, mit Castopod zu interagieren.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast-Besitzer', + 'description' => 'Der Podcast-Besitzer.', + ], + 'admin' => [ + 'title' => 'Administrator', + 'description' => 'Hat die vollständige Kontrolle über Podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Verwaltet Inhalte und Veröffentlichungen von Podcast #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Verwaltet Inhalte von Podcast #{id}, kann diese aber nicht veröffentlichen.', + ], + 'guest' => [ + 'title' => 'Gast', + 'description' => 'Allgemeiner Mitwirkender des Podcasts #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Kann das Dashboard und Analysen des Podcasts #{id} einsehen.', + 'edit' => 'Kann Podcast #{id} bearbeiten.', + 'delete' => 'Kann Podcast #{id} löschen.', + 'manage-import' => 'Kann den importierten Podcast #{id} synchronisieren.', + 'manage-persons' => 'Kann Abonnements des Podcasts #{id} verwalten.', + 'manage-subscriptions' => 'Kann Abonnements des Podcasts #{id} verwalten.', + 'manage-contributors' => 'Kann Mitwirkende des Podcasts #{id} verwalten.', + 'manage-platforms' => 'Kann Plattform-Links des Podcasts #{id} verwalten.', + 'manage-publications' => 'Kann Podcast #{id} veröffentlichen.', + 'manage-notifications' => 'Kann Benachrichtigungen des Podcasts #{id} einsehen und als gelesen markieren.', + 'interact-as' => 'Kann als Podcast #{id} interagieren, um Beiträge zu favorisieren, zu teilen oder diese zu beantworten.', + 'episodes' => [ + 'view' => 'Kann Dashboards und Analysen von Episoden des Podcasts #{id} einsehen.', + 'create' => 'Kann Folgen für Podcast #{id} erstellen.', + 'edit' => 'Kann Folgen von Podcast #{id} bearbeiten.', + 'delete' => 'Kann Folgen von Podcast #{id} löschen.', + 'manage-persons' => 'Kann Personen von Episoden des Podcasts #{id} verwalten.', + 'manage-clips' => 'Kann Videoclips und Soundbites des Podcasts #{id} verwalten.', + 'manage-publications' => 'Kann Episoden und Posts von Podcast #{id} veröffentlichen/zurückziehen.', + 'manage-comments' => 'Kann Kommentare von Folgen des Podcasts #{id} erstellen und löschen.', + ], + ], + + // missing keys + 'code' => 'Ihr 6-stelliger Code', + + 'set_password' => 'Legen Sie Ihr Passwort fest', + + // Welcome email + 'welcomeSubject' => 'Sie wurden zu {siteName} eingeladen', + 'emailWelcomeMailBody' => 'Ein Account auf {domain} wurde für Sie angelegt, klicken Sie auf den unten stehenden Login-Link, um Ihr Passwort festzulegen. Der Link ist mit Versand der Mail für {numberOfHours} gültig.', +]; diff --git a/modules/Auth/Language/de/Contributor.php b/modules/Auth/Language/de/Contributor.php new file mode 100644 index 00000000..27ff60dc --- /dev/null +++ b/modules/Auth/Language/de/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast-Administratoren', + 'view' => "{username}'s Mitwirkung an {podcastTitle}", + 'add' => 'Mitwirkenden zufügen', + 'add_contributor' => 'Mitwirkenden zufügen für {0}', + 'edit_role' => 'Rolle aktualisieren für {0}', + 'edit' => 'Bearbeiten', + 'remove' => 'Entfernen', + 'list' => [ + 'username' => 'Benutzername', + 'role' => 'Rolle', + ], + 'form' => [ + 'user' => 'Benutzer', + 'user_placeholder' => 'Benutzer auswählen…', + 'role' => 'Rolle', + 'role_placeholder' => 'Rolle auswählen…', + 'submit_add' => 'Administrator zufügen', + 'submit_edit' => 'Rolle aktualisieren', + ], + 'delete_form' => [ + 'title' => '{contributor} entfernen', + 'disclaimer' => + 'Sie sind dabei, {contributor} von den Mitwirkenden zu entfernen. Es wird kein Zugriff mehr auf "{podcastTitle}" möglich sein.', + 'understand' => 'Ich verstehe, ich möchte {contributor} von "{podcastTitle}" entfernen', + 'submit' => 'Entfernen', + ], + 'messages' => [ + 'editSuccess' => 'Rolle erfolgreich geändert!', + 'editOwnerError' => "Sie können den Podcast-Besitzer nicht verändern!", + 'removeOwnerError' => "Der Podcast Inhaber kann nicht entfernt werden!", + 'removeSuccess' => + '{username} wurde von {podcastTitle} entfernt', + 'alreadyAddedError' => + "Der Adminstrator wurde bereits zugefügt!", + ], +]; diff --git a/modules/Auth/Language/de/MyAccount.php b/modules/Auth/Language/de/MyAccount.php new file mode 100644 index 00000000..578045c5 --- /dev/null +++ b/modules/Auth/Language/de/MyAccount.php @@ -0,0 +1,18 @@ + 'Meine Kontoinformationen', + 'changePassword' => 'Mein Passwort ändern', + 'messages' => [ + 'wrongPasswordError' => "Das eingegebene Passwort ist falsch. Erneut versuchen.", + 'passwordChangeSuccess' => 'Das Passwort wurde erfolgreich geändert!', + ], +]; diff --git a/modules/Auth/Language/de/User.php b/modules/Auth/Language/de/User.php new file mode 100644 index 00000000..68649b0a --- /dev/null +++ b/modules/Auth/Language/de/User.php @@ -0,0 +1,60 @@ + "Die Rolle(n) von {username} bearbeiten", + 'ban' => 'Sperren', + 'unban' => 'Entsperren', + 'delete' => 'Löschen', + 'create' => 'Neuer Benutzer', + 'view' => "{username}-Infos", + 'all_users' => 'Alle Benutzer', + 'list' => [ + 'user' => 'Benutzer', + 'role' => 'Rolle', + 'banned' => 'Gesperrt?', + ], + 'form' => [ + 'email' => 'E-mail', + 'username' => 'Benutzername', + 'password' => 'Passwort', + 'new_password' => 'Neues Passwort', + 'role' => 'Rolle', + 'roles' => 'Rollen', + 'permissions' => 'Berechtigungen', + 'submit_create' => 'Benutzer erstellen', + 'submit_edit' => 'Speichern', + 'submit_password_change' => 'Verändern!', + ], + 'delete_form' => [ + 'title' => '{user} löschen', + 'disclaimer' => + "Sie sind dabei {user} dauerhaft zu löschen. Es wird für den Benutzer nicht mehr möglich sein, den Admin-Bereich zu nutzen.", + 'understand' => 'Ich verstehe, Ich will {user} dauerhaft löschen', + 'submit' => 'Löschen', + ], + 'messages' => [ + 'createSuccess' => + 'Benutzer wurde erfolgreich erstellt! {username} wird bei der ersten Authentifizierung zu einer Passwortzurücksetzung aufgefordert.', + 'roleEditSuccess' => + "{username}'s Rollen wurden erfolgreich aktualisiert.", + 'banSuccess' => '{username} wurde gebannt.', + 'unbanSuccess' => '{username} wurde entbannt.', + 'editOwnerError' => + '{username} ist Eigentümer der Instanz, Eigentümer können nicht gelöscht werden…', + 'banSuperAdminError' => + '{username} ist ein Superadmin, man bannt nicht einfach einen Superadmin…', + 'deleteOwnerError' => + '{username} ist Eigentümer der Instanz, Eigentümer können nicht gelöscht werden…', + 'deleteSuperAdminError' => + '{username} ist ein Superadmin, man löscht nicht einfach einen Superadmin…', + 'deleteSuccess' => '{username} wurde gelöscht.', + ], +]; diff --git a/modules/Auth/Language/el/Auth.php b/modules/Auth/Language/el/Auth.php new file mode 100644 index 00000000..1ba3c9ae --- /dev/null +++ b/modules/Auth/Language/el/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Ιδιοκτήτης Διακομιστή', + 'description' => 'Ο ιδιοκτήτης του Castopod.', + ], + 'superadmin' => [ + 'title' => 'Υπερδιαχειριστής', + 'description' => 'Έχει πλήρη έλεγχο του Castopod.', + ], + 'manager' => [ + 'title' => 'Διαχειριστής', + 'description' => 'Διαχείριση περιεχομένου του Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Γενικοί χρήστες του Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Μπορεί να έχει πρόσβαση στην περιοχή διαχείρισης Castopod.', + 'admin.settings' => 'Μπορεί να έχει πρόσβαση στις ρυθμίσεις Castopod.', + 'users.manage' => 'Μπορεί να διαχειριστεί τους χρήστες Castopod.', + 'persons.manage' => 'Μπορεί να διαχειριστεί τα άτομα.', + 'pages.manage' => 'Μπορεί να διαχειριστεί τις σελίδες.', + 'podcasts.view' => 'Μπορεί να δει όλα τα podcasts.', + 'podcasts.create' => 'Μπορεί να δημιουργήσει νέα podcasts.', + 'podcasts.import' => 'Μπορεί να εισάγει podcasts.', + 'fediverse.manage-blocks' => 'Μπορεί να εμποδίσει τους ψευτογενείς ηθοποιούς/τομείς να αλληλεπιδρούν με το Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Ιδιοκτήτης Podcast', + 'description' => 'Ο ιδιοκτήτης του podcast.', + ], + 'admin' => [ + 'title' => 'Διαχειριστής', + 'description' => 'Έχει πλήρη έλεγχο του podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Εκδότης', + 'description' => 'Διαχειρίζεται περιεχόμενο και δημοσιεύσεις του podcast #{id}.', + ], + 'author' => [ + 'title' => 'Συντάκτης', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Επισκέπτης', + 'description' => 'Γενικός συντελεστής του podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/el/Contributor.php b/modules/Auth/Language/el/Contributor.php new file mode 100644 index 00000000..1acec63a --- /dev/null +++ b/modules/Auth/Language/el/Contributor.php @@ -0,0 +1,47 @@ + 'Συντελεστές Podcast', + 'view' => "Ο χρήστης {username} συνείσφερε στο {podcastTitle}", + 'add' => 'Προσθήκη συντελεστή', + 'add_contributor' => 'Προσθέστε έναν συνεισφέροντα για {0}', + 'edit_role' => 'Ενημέρωση ρόλου για {0}', + 'edit' => 'Επεξεργασία', + 'remove' => 'Διαγραφή', + 'list' => [ + 'username' => 'Όνομα Χρήστη', + 'role' => 'Ρόλος', + ], + 'form' => [ + 'user' => 'Χρήστης', + 'user_placeholder' => 'Επιλέξτε χρήστη…', + 'role' => 'Ρόλος', + 'role_placeholder' => 'Επιλέξτε το ρόλο του χρήστη…', + 'submit_add' => 'Προσθήκη συντελεστή', + 'submit_edit' => 'Ενημέρωση ρόλου', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "Δεν μπορείτε να καταργήσετε τον ιδιοκτήτη podcast!", + 'removeSuccess' => + 'Έχετε αφαιρέσει με επιτυχία τον χρήστη {username} από το {podcastTitle}', + 'alreadyAddedError' => + "Ο συνεισφέροντας που προσπαθείτε να προσθέσετε έχει ήδη προστεθεί!", + ], +]; diff --git a/modules/Auth/Language/el/MyAccount.php b/modules/Auth/Language/el/MyAccount.php new file mode 100644 index 00000000..fe2dc34e --- /dev/null +++ b/modules/Auth/Language/el/MyAccount.php @@ -0,0 +1,18 @@ + 'Πληροφορίες Λογαριασμού', + 'changePassword' => 'Αλλαγή κωδικού πρόσβασης', + 'messages' => [ + 'wrongPasswordError' => "Έχετε εισάγει λάθος κωδικό πρόσβασης, προσπαθήστε ξανά.", + 'passwordChangeSuccess' => 'Ο κωδικός πρόσβασής σας άλλαξε με επιτυχία!', + ], +]; diff --git a/modules/Auth/Language/el/User.php b/modules/Auth/Language/el/User.php new file mode 100644 index 00000000..05bc0e1d --- /dev/null +++ b/modules/Auth/Language/el/User.php @@ -0,0 +1,60 @@ + "Επεξεργασία ρόλων {username}", + 'ban' => 'Αποκλεισμός', + 'unban' => 'Κατάργηση αποκλεισμού', + 'delete' => 'Διαγραφή', + 'create' => 'Νέος χρήστης', + 'view' => "πληροφορίες του {username}", + 'all_users' => 'Όλοι οι χρήστες', + 'list' => [ + 'user' => 'Χρήστης', + 'role' => 'Ρόλος', + 'banned' => 'Αποκλεισμένος;', + ], + 'form' => [ + 'email' => 'Ηλεκτρονικό ταχυδρομείο', + 'username' => 'Όνομα Χρήστη', + 'password' => 'Κωδικόs πρόσβασης', + 'new_password' => 'Νέος Κωδικός Πρόσβασης', + 'role' => 'Ρόλος', + 'roles' => 'Ρόλοι', + 'permissions' => 'Δικαιώματα', + 'submit_create' => 'Δημιουργία χρήστη', + 'submit_edit' => 'Αποθήκευση', + 'submit_password_change' => 'Αλλαγή!', + ], + 'delete_form' => [ + 'title' => 'Διαγραφή {user}', + 'disclaimer' => + "Πρόκειται να διαγράψετε το {user} οριστικά. Δεν θα μπορούν πλέον να έχουν πρόσβαση στην περιοχή διαχείρισης.", + 'understand' => 'Καταλαβαίνω, θέλω να διαγράψω {user} μόνιμα', + 'submit' => 'Διαγραφή', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "οι ρόλοι του {username} έχουν ενημερωθεί με επιτυχία.", + 'banSuccess' => 'Ο/Η {username} έχει αποκλειστεί.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/en/Auth.php b/modules/Auth/Language/en/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/en/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/en/Contributor.php b/modules/Auth/Language/en/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/en/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/en/MyAccount.php b/modules/Auth/Language/en/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/en/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/en/User.php b/modules/Auth/Language/en/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/en/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/es/Auth.php b/modules/Auth/Language/es/Auth.php new file mode 100644 index 00000000..9f82a3cc --- /dev/null +++ b/modules/Auth/Language/es/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Propietario de Instancia', + 'description' => 'Propietario de Castopod.', + ], + 'superadmin' => [ + 'title' => 'Super administrador', + 'description' => 'Tiene control completo sobre Castopod.', + ], + 'manager' => [ + 'title' => 'Administrador', + 'description' => 'Administrar contenido de Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Usuarios generales de Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Puedes acceder al área de administración de Castopod.', + 'admin.settings' => 'Puede acceder a la configuración de Castopod.', + 'users.manage' => 'Puede administrar usuarios de Castopod.', + 'persons.manage' => 'Puede administrar personas.', + 'pages.manage' => 'Puede administrar páginas.', + 'podcasts.view' => 'Puede ver todos los podcasts.', + 'podcasts.create' => 'Puede crear nuevos podcasts.', + 'podcasts.import' => 'Puede importar podcasts.', + 'fediverse.manage-blocks' => 'Puedes bloquear la interacción de actores/dominios del fediverso con Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Propietario de Podcast', + 'description' => 'El propietario del podcast.', + ], + 'admin' => [ + 'title' => 'Administrador', + 'description' => 'Tiene el control completo del podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Gestiona el contenido y las publicaciones del podcast #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Gestiona el contenido del podcast #{id} pero no puede publicarlo.', + ], + 'guest' => [ + 'title' => 'Invitado', + 'description' => 'Colaborador general del podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Puede ver el panel de control y analíticas del episodio #{id}.', + 'edit' => 'Puede editar el podcast #{id}.', + 'delete' => 'Puede borrar el podcast #{id}.', + 'manage-import' => 'Puede sincronizar el podcast importado #{id}.', + 'manage-persons' => 'Puede administrar las suscripciones del podcast #{id}.', + 'manage-subscriptions' => 'Puede administrar las suscripciones del podcast #{id}.', + 'manage-contributors' => 'Puede administrar colaboradores del podcast #{id}.', + 'manage-platforms' => 'Puede establecer/eliminar enlaces a la plataforma del podcast #{id}.', + 'manage-publications' => 'Puede publicar el podcast #{id}.', + 'manage-notifications' => 'Puede ver y marcar las notificaciones como leídas para podcast #{id}.', + 'interact-as' => 'Puede interactuar como el podcast #{id} para marcar como favarito, compartir o responder a las publicaciones.', + 'episodes' => [ + 'view' => 'Puede ver el panel de control y analíticas del episodio #{id}.', + 'create' => 'Puede crear episodios para el podcast #{id}.', + 'edit' => 'Puede editar episodios del podcast #{id}.', + 'delete' => 'Puede borrar episodios del podcast #{id}.', + 'manage-persons' => 'Puede administrar las personas de los episodios del podcast #{id}.', + 'manage-clips' => 'Puedes administrar video clips o sonidos del podcast #{id}.', + 'manage-publications' => 'Puede publicar/despublicar episodios y publicaciones del podcast #{id}.', + 'manage-comments' => 'Puede crear/eliminar los comentarios de episodio del podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Introduce un código de 6 dígitos', + + 'set_password' => 'Establece tu contraseña', + + // Welcome email + 'welcomeSubject' => 'Has sido invitado a {siteName}', + 'emailWelcomeMailBody' => 'Una cuenta fue creada para usted en {domain}, haga clic en el enlace de inicio de sesión de abajo para establecer su contraseña. El enlace es válido durante {numberOfHours} horas después de enviar este correo electrónico.', +]; diff --git a/modules/Auth/Language/es/Contributor.php b/modules/Auth/Language/es/Contributor.php new file mode 100644 index 00000000..d5b3a256 --- /dev/null +++ b/modules/Auth/Language/es/Contributor.php @@ -0,0 +1,47 @@ + 'Colaboradores de Podcast', + 'view' => "Contribución de {username} a {podcastTitle}", + 'add' => 'Añadir colaborador', + 'add_contributor' => 'Agregar contrato a {0}', + 'edit_role' => 'Actualizar rol para {0}', + 'edit' => 'Editar', + 'remove' => 'Eliminar', + 'list' => [ + 'username' => 'Nombre de usuario', + 'role' => 'Cargo', + ], + 'form' => [ + 'user' => 'Usuario', + 'user_placeholder' => 'Seleccione un usuario…', + 'role' => 'Cargo', + 'role_placeholder' => 'Seleccionar su rol…', + 'submit_add' => 'Añadir colaborador', + 'submit_edit' => 'Actualizar Cargo', + ], + 'delete_form' => [ + 'title' => 'Eliminar {contributor}', + 'disclaimer' => + 'Estás a punto de eliminar a {contributor} de los colaboradores. Ya no podrán acceder a "{podcastTitle}".', + 'understand' => 'Entiendo, quiero eliminar a {contributor} de "{podcastTitle}"', + 'submit' => 'Eliminar', + ], + 'messages' => [ + 'editSuccess' => '¡Rol cambiado con éxito!', + 'editOwnerError' => "¡No puedes editar el dueño del podcast!", + 'removeOwnerError' => "¡No puedes eliminar al dueño del podcast!", + 'removeSuccess' => + 'Has eliminado con éxito a {username} de {podcastTitle}', + 'alreadyAddedError' => + "¡El colaborador que estás intentando añadir ya ha sido añadido!", + ], +]; diff --git a/modules/Auth/Language/es/MyAccount.php b/modules/Auth/Language/es/MyAccount.php new file mode 100644 index 00000000..c9027a42 --- /dev/null +++ b/modules/Auth/Language/es/MyAccount.php @@ -0,0 +1,18 @@ + 'Información de mi Cuenta', + 'changePassword' => 'Cambiar mi contraseña', + 'messages' => [ + 'wrongPasswordError' => "Ingresaste la contraseña equivocada. Por favor intenta nuevamente.", + 'passwordChangeSuccess' => '¡Tu contraseña ha sido modificada con éxito!', + ], +]; diff --git a/modules/Auth/Language/es/User.php b/modules/Auth/Language/es/User.php new file mode 100644 index 00000000..ce11ceb6 --- /dev/null +++ b/modules/Auth/Language/es/User.php @@ -0,0 +1,60 @@ + "Editar rol de {username}", + 'ban' => 'Banear', + 'unban' => 'Desbanear', + 'delete' => 'Borrar', + 'create' => 'Nuevo usuario', + 'view' => "Información de {username}", + 'all_users' => 'Todos los usuarios', + 'list' => [ + 'user' => 'Usuario', + 'role' => 'Rol', + 'banned' => '¿Baneado?', + ], + 'form' => [ + 'email' => 'Correo electrónico', + 'username' => 'Nombre de usuario', + 'password' => 'Contraseña', + 'new_password' => 'Nueva Contraseña', + 'role' => 'Rol', + 'roles' => 'Roles', + 'permissions' => 'Permisos', + 'submit_create' => 'Crear usuario', + 'submit_edit' => 'Guardar', + 'submit_password_change' => '¡Cambiar!', + ], + 'delete_form' => [ + 'title' => 'Eliminar {user}', + 'disclaimer' => + "Estás a punto de eliminar {user} permanentemente. Ya no podrán acceder al área de administración.", + 'understand' => 'Entiendo, quiero eliminar {user} permanentemente', + 'submit' => 'Eliminar', + ], + 'messages' => [ + 'createSuccess' => + '¡Usuario creado con éxito! Se le pedirá a {username} que restablezca la contraseña en la primera autenticación.', + 'roleEditSuccess' => + "Los roles de {username} se han actualizado correctamente.", + 'banSuccess' => '{username} ha sido baneado.', + 'unbanSuccess' => '{username} ha sido desbaneado.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} es un superadmin, no puedes banear a un superadministrador…', + 'deleteOwnerError' => + '{username} es el propietario de la instancia, uno no simplemente elimina al propietario…', + 'deleteSuperAdminError' => + '{username} es un superadmin, no puedes borrar a un superadministrador…', + 'deleteSuccess' => '{username} ha sido eliminado.', + ], +]; diff --git a/modules/Auth/Language/eu/Auth.php b/modules/Auth/Language/eu/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/eu/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/eu/Contributor.php b/modules/Auth/Language/eu/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/eu/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/eu/MyAccount.php b/modules/Auth/Language/eu/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/eu/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/eu/User.php b/modules/Auth/Language/eu/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/eu/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/fa/Auth.php b/modules/Auth/Language/fa/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/fa/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/fa/Contributor.php b/modules/Auth/Language/fa/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/fa/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/fa/MyAccount.php b/modules/Auth/Language/fa/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/fa/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/fa/User.php b/modules/Auth/Language/fa/User.php new file mode 100644 index 00000000..b9804342 --- /dev/null +++ b/modules/Auth/Language/fa/User.php @@ -0,0 +1,60 @@ + "ویراش نقش {username}", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'حذف', + 'create' => 'کاربر جدید', + 'view' => "اطّلاعات {username}", + 'all_users' => 'تمامی کاربران', + 'list' => [ + 'user' => 'کاربر', + 'role' => 'نقش', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'رایانامه', + 'username' => 'نام‌کاربری', + 'password' => 'گذرواژه', + 'new_password' => 'گذرواژه‌ٔ جدید', + 'role' => 'نقش', + 'roles' => 'نقش‌ها', + 'permissions' => 'اجازه‌ها', + 'submit_create' => 'ایجاد کاربر', + 'submit_edit' => 'ذخیره', + 'submit_password_change' => 'تغییر!', + ], + 'delete_form' => [ + 'title' => 'حذف {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'حذف', + ], + 'messages' => [ + 'createSuccess' => + 'کاربر با موفّقیت ساخته شد! رایانامهٔ خوش‌آمدی به همراه پیوند ورود برای {username} فرستاده شد. در نخستین ورودش اعلانی برای بازنشانی گذرواژه دریافت خواهد کرد.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} مالک نمونه است. کسی به سادگی مالک را تغییر نمی‌دهد…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/fr-ca/Auth.php b/modules/Auth/Language/fr-ca/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/fr-ca/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/fr-ca/Contributor.php b/modules/Auth/Language/fr-ca/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/fr-ca/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/fr-ca/MyAccount.php b/modules/Auth/Language/fr-ca/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/fr-ca/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/fr-ca/User.php b/modules/Auth/Language/fr-ca/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/fr-ca/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/fr/Auth.php b/modules/Auth/Language/fr/Auth.php new file mode 100644 index 00000000..4afdf596 --- /dev/null +++ b/modules/Auth/Language/fr/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Propriétaire de l\'instance', + 'description' => 'Le propriétaire du Castopod.', + ], + 'superadmin' => [ + 'title' => 'Super administrat·rice·eur', + 'description' => 'A un contrôle complet sur Castopod.', + ], + 'manager' => [ + 'title' => 'Gestionnaire', + 'description' => 'Gère le contenu de Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcast·rice·eur', + 'description' => 'Utilisateurs généraux de Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Peut accéder à la zone d\'administration Castopod.', + 'admin.settings' => 'Peut accéder aux paramètres de Castopod.', + 'users.manage' => 'Peut gérer les utilisateurs de Castopod.', + 'persons.manage' => 'Permet de gérer les personnes.', + 'pages.manage' => 'Permet de gérer les pages.', + 'podcasts.view' => 'Peut voir tous les podcasts.', + 'podcasts.create' => 'Peut créer de nouveaux podcasts.', + 'podcasts.import' => 'Peut importer des podcasts.', + 'fediverse.manage-blocks' => 'Peut empêcher des act·rice·eur·s/domaines d\'interagir avec Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Propriétaire du Podcast', + 'description' => 'Le/la propriétaire du podcast.', + ], + 'admin' => [ + 'title' => 'Administrateur', + 'description' => 'A un contrôle total sur le podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Éditeur', + 'description' => 'Gère le contenu et les publications du podcast #{id}.', + ], + 'author' => [ + 'title' => 'Auteur / Autrice', + 'description' => 'Gère le contenu du podcast #{id} , mais ne peut pas le publier.', + ], + 'guest' => [ + 'title' => 'Invité', + 'description' => 'Contributeur général du podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Peut voir le tableau de bord et les analyses du podcast #{id}.', + 'edit' => 'Peut éditer le podcast #{id}.', + 'delete' => 'Peut supprimer le podcast #{id}.', + 'manage-import' => 'Peut synchroniser le podcast importé #{id}.', + 'manage-persons' => 'Permet de gérer les abonnements au podcast #{id}.', + 'manage-subscriptions' => 'Permet de gérer les abonnements au podcast #{id}.', + 'manage-contributors' => 'Permet de gérer les contributeurs du podcast #{id}.', + 'manage-platforms' => 'Peut configurer/supprimer les liens de la plateforme du podcast #{id}.', + 'manage-publications' => 'Peut publier le podcast #{id}.', + 'manage-notifications' => 'Peut afficher et marquer les notifications comme lues pour le podcast #{id}.', + 'interact-as' => 'Peut interagir en tant que podcast #{id} pour mettre en favori, partager ou répondre aux messages.', + 'episodes' => [ + 'view' => 'Peut voir le tableau de bord et les statistiques du podcast #{id}.', + 'create' => 'Peut créer des épisodes pour le podcast #{id}.', + 'edit' => 'Peut modifier les épisodes du podcast #{id}.', + 'delete' => 'Peut supprimer les épisodes du podcast #{id}.', + 'manage-persons' => 'Peut gérer les intervenants des épisodes du podcast #{id}.', + 'manage-clips' => 'Permet de gérer les clips vidéo ou les parties sonores du podcast #{id}.', + 'manage-publications' => 'Peut publier/dépublier des épisodes et des messages de podcast #{id}.', + 'manage-comments' => 'Peut créer/supprimer les commentaires de l\'épisode du podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Votre code à 6 chiffres', + + 'set_password' => 'Choisis ton mot de passe', + + // Welcome email + 'welcomeSubject' => 'Vous avez été invité·e à rejoindre {siteName}', + 'emailWelcomeMailBody' => 'Un compte a été créé pour vous sur {domain}, cliquez sur le lien de connexion ci-dessous pour définir votre mot de passe. Le lien est valide pendant {numberOfHours} heures après l\'envoi de cet e-mail.', +]; diff --git a/modules/Auth/Language/fr/Contributor.php b/modules/Auth/Language/fr/Contributor.php new file mode 100644 index 00000000..a9006130 --- /dev/null +++ b/modules/Auth/Language/fr/Contributor.php @@ -0,0 +1,47 @@ + 'Contributeurs du podcast', + 'view' => "Contribution de {username} à {podcastTitle}", + 'add' => 'Ajouter un contributeur', + 'add_contributor' => 'Ajouter un contributeur pour {0}', + 'edit_role' => 'Modifier le rôle de {0}', + 'edit' => 'Modifier', + 'remove' => 'Supprimer', + 'list' => [ + 'username' => 'Identifiant', + 'role' => 'Rôle', + ], + 'form' => [ + 'user' => 'Utilisateur', + 'user_placeholder' => 'Sélectionnez un utilisateur…', + 'role' => 'Rôle', + 'role_placeholder' => 'Sélectionnez son rôle…', + 'submit_add' => 'Ajouter le contributeur', + 'submit_edit' => 'Mettre à jour le rôle', + ], + 'delete_form' => [ + 'title' => 'Supprimer {contributor}', + 'disclaimer' => + 'Vous êtes sur le point de supprimer {contributor} des contributeurs. Ils ne pourront plus accéder à "{podcastTitle}".', + 'understand' => 'Je comprends, je veux retirer {contributor} de "{podcastTitle}"', + 'submit' => 'Retirer', + ], + 'messages' => [ + 'editSuccess' => 'Rôle modifié avec succès !', + 'editOwnerError' => "Vous ne pouvez pas modifier le propriétaire du podcast !", + 'removeOwnerError' => "Vous ne pouvez pas retirer le propriétaire du podcast !", + 'removeSuccess' => + 'Vous avez retiré {username} de {podcastTitle}', + 'alreadyAddedError' => + "Le contributeur que vous essayez d’ajouter est déjà présent.", + ], +]; diff --git a/modules/Auth/Language/fr/MyAccount.php b/modules/Auth/Language/fr/MyAccount.php new file mode 100644 index 00000000..824e35cb --- /dev/null +++ b/modules/Auth/Language/fr/MyAccount.php @@ -0,0 +1,18 @@ + 'Informations relatives à mon compte', + 'changePassword' => 'Modifier mon mot de passe', + 'messages' => [ + 'wrongPasswordError' => "Le mot de passe que vous avez saisi est invalide.", + 'passwordChangeSuccess' => 'Le mot de passe a été modifié avec succès !', + ], +]; diff --git a/modules/Auth/Language/fr/User.php b/modules/Auth/Language/fr/User.php new file mode 100644 index 00000000..91139158 --- /dev/null +++ b/modules/Auth/Language/fr/User.php @@ -0,0 +1,60 @@ + "Modifier le rôle de {username}", + 'ban' => 'Bloquer', + 'unban' => 'Débloquer', + 'delete' => 'Supprimer', + 'create' => 'Créer un utilisateur', + 'view' => "Informations de {username}", + 'all_users' => 'Tous les utilisateurs', + 'list' => [ + 'user' => 'Utilisateurs', + 'role' => 'Rôle', + 'banned' => 'Bloqué ?', + ], + 'form' => [ + 'email' => 'E-mail', + 'username' => 'Identifiant', + 'password' => 'Mot de passe', + 'new_password' => 'Nouveau mot de passe', + 'role' => 'Rôle', + 'roles' => 'Rôles', + 'permissions' => 'Permissions', + 'submit_create' => 'Créer un utilisateur', + 'submit_edit' => 'Enregistrer', + 'submit_password_change' => 'Valider !', + ], + 'delete_form' => [ + 'title' => 'Supprimer {user}', + 'disclaimer' => + "Vous êtes sur le point de supprimer {user} définitivement. Ils ne pourront plus accéder à la zone d'administration.", + 'understand' => 'Je comprends, je veux supprimer {user} définitivement', + 'submit' => 'Supprimer', + ], + 'messages' => [ + 'createSuccess' => + 'Utilisateur créé avec succès ! {username} devra modifier son mot de passe à la première authentification.', + 'roleEditSuccess' => + "Les rôles de {username} ont été mis à jour avec succès.", + 'banSuccess' => '{username} a été bloqué.', + 'unbanSuccess' => '{username} a été débloqué.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} est un super-utilisateur, on ne bloque pas un super-utilisateur comme ça…', + 'deleteOwnerError' => + '{username} est le propriétaire de l\'instance, on ne supprime pas le propriétaire…', + 'deleteSuperAdminError' => + '{username} est un super-utilisateur, on ne supprime pas un super-utilisateur comme ça…', + 'deleteSuccess' => '{username} a été supprimé.', + ], +]; diff --git a/modules/Auth/Language/fr2/Auth.php b/modules/Auth/Language/fr2/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/fr2/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/fr2/Contributor.php b/modules/Auth/Language/fr2/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/fr2/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/fr2/MyAccount.php b/modules/Auth/Language/fr2/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/fr2/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/fr2/User.php b/modules/Auth/Language/fr2/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/fr2/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/gd/Auth.php b/modules/Auth/Language/gd/Auth.php new file mode 100644 index 00000000..2ff1f7d8 --- /dev/null +++ b/modules/Auth/Language/gd/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Sealbhadair an ionstans', + 'description' => 'Cò leis a tha an Castopod seo.', + ], + 'superadmin' => [ + 'title' => 'Sàr-rianaire', + 'description' => 'Smachd gu lèir air Castopod.', + ], + 'manager' => [ + 'title' => 'Manaidsear', + 'description' => 'Stiùireadh susbaint Chastopod.', + ], + 'podcaster' => [ + 'title' => 'Pod-chraoladair', + 'description' => 'Luchd-cleachdaidh coitcheann Chastopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => '’S urrainn dhaibh raon rianachd Chastopod inntrigeadh.', + 'admin.settings' => '’S urrainn dhaibh roghainnean Chastopod inntrigeadh.', + 'users.manage' => '’S urrainn dhaibh luchdc-leachdaidh Chastopod a stiùireadh.', + 'persons.manage' => '’S urrainn dhaibh daoine a stiùireadh.', + 'pages.manage' => '’S urrainn dhaibh duilleagan a stiùireadh.', + 'podcasts.view' => 'Chì iad a h-uile pod-chraoladh.', + 'podcasts.create' => '’S urrainn dhaibh pod-chraolaidhean ùra a chruthachadh.', + 'podcasts.import' => '’S urrainn dhaibh pod-chraolaidhean ion-phortadh.', + 'fediverse.manage-blocks' => '’S urrainn dhaibh actairean/àrainnean a cho-shaoghail a bhacadh o eadar-ghabhail le Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Seilbheadair a’ phod-chraolaidh', + 'description' => 'Cò leis a tha am pod-chraoladh.', + ], + 'admin' => [ + 'title' => 'Rianaire', + 'description' => 'Smachd gu lèir air air a’ phod-chraoladh #{id}.', + ], + 'editor' => [ + 'title' => 'Deasaiche', + 'description' => 'A’ stiùireadh susbaint is foillseachaidhean a’ phod-chraoladh #{id}.', + ], + 'author' => [ + 'title' => 'Ùghdar', + 'description' => 'A’ stiùireadh susbaint a’ phod-chraolaidh #{id} ach gun chomas foillseachaidh.', + ], + 'guest' => [ + 'title' => 'Aoigh', + 'description' => 'Neach-cuideachaidh a’ phod-chraolaidh #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Cead an deas-bhòrd agus anailiseachd a’ phod-chraolaidh #{id} a shealltainn.', + 'edit' => '’S urrainn dhaibh am pod-chraoladh #{id} a dheasachadh.', + 'delete' => '’S urrainn dhaibh am pod-chraoladh #{id} a sguabadh às.', + 'manage-import' => '’S urrainn dhaibh am pod-chraoladh #{id} air ion-phortadh a shioncronachadh.', + 'manage-persons' => '’S urrainn dhaibh na fo-sgrìobhaidhean air a’ phod-chraoladh #{id} a stiùireadh.', + 'manage-subscriptions' => '’S urrainn dhaibh na fo-sgrìobhaidhean air a’ phod-chraoladh #{id} a stiùireadh.', + 'manage-contributors' => '’S urrainn dhaibh an luchd-cuideachaidh aig a’ phod-chraoladh #{id} a stiùireadh.', + 'manage-platforms' => '’S urrainn dhaibh ceanglaichean-ùrlair a’ phod-chraolaidh #{id} a shuidheachadh/a thoirt air falbh.', + 'manage-publications' => '’S urrainn dhaibh am pod-chraoladh #{id} fhoillseachadh.', + 'manage-notifications' => 'Chì iad brathan a’ phod-chraolaidh #{id} agus ’s urrainn dhaibh comharra a chur gun deach an leughadh.', + 'interact-as' => '’S urrainn dhaibh eadar-ghabhail ’na phod-chraoladh #{id} airson annsachdan, co-roinneadh is freagairtean do phostaichean.', + 'episodes' => [ + 'view' => 'Chì iad deas-bhùird is anailiseachd do dh’eapasodan a’ phod-chraolaidh #{id}.', + 'create' => '’S urrainn dhaibh eapasodan a chruthachadh dhan phod-chraoladh #{id}.', + 'edit' => '’S urrainn dhaibh eapasodan a’ phod-chraolaidh #{id} a dheasachadh.', + 'delete' => '’S urrainn dhaibh eapasodan a’ phod-chraolaidh #{id} a sguabadh às.', + 'manage-persons' => '’S urrainn dhaibh daoine nan eapasodan aig a’ phod-chraoladh #{id} a stiùireadh.', + 'manage-clips' => '’S urrainn dhaibh cliopaichean video no blasan-fuaime aig a’ phod-chraoladh #{id} a stiùireadh.', + 'manage-publications' => '’S urrainn dhaibh eapasodan is postaichean a’ phod-chraolaidh #{id} fhoillseachadh/neo-fhoillseachadh.', + 'manage-comments' => '’S urrainn dhaibh beachdan air eapasod a’ phod-chraolaidh #{id} a chruthachadh/a thoirt air falbh.', + ], + ], + + // missing keys + 'code' => 'An còd 6-àireamhach agad', + + 'set_password' => 'Suidhich am facal-faire agad', + + // Welcome email + 'welcomeSubject' => 'Fhuair thu cuireadh gu {siteName}', + 'emailWelcomeMailBody' => 'Chaidh cunntas a chruthachadh dhut air {domain}, briog air ceangal a’ chlàraidh a-steach gu h-ìosal airson am facal-faire agad a shuidheachadh. Bidh an ceangal dligheach fad {numberOfHours} uair a thìde às dèidh cur a’ phuist-d seo.', +]; diff --git a/modules/Auth/Language/gd/Contributor.php b/modules/Auth/Language/gd/Contributor.php new file mode 100644 index 00000000..a6154a55 --- /dev/null +++ b/modules/Auth/Language/gd/Contributor.php @@ -0,0 +1,47 @@ + 'Luchd-cuideachaidh a’ phod-chraolaidh', + 'view' => "Na chuir {username} ri {podcastTitle}", + 'add' => 'Cuir neach-cuideachaidh ris', + 'add_contributor' => 'Cuir neach-cuideachaidh ris airson {0}', + 'edit_role' => 'Ùraich an dreuchd airson {0}', + 'edit' => 'Deasaich', + 'remove' => 'Thoir air falbh', + 'list' => [ + 'username' => 'Ainm-cleachdaiche', + 'role' => 'Dreuchd', + ], + 'form' => [ + 'user' => 'Cleachdaiche', + 'user_placeholder' => 'Tagh cleachdaiche…', + 'role' => 'Dreuchd', + 'role_placeholder' => 'Tagh dreuchd dhaibh…', + 'submit_add' => 'Cuir neach-cuideachaidh ris', + 'submit_edit' => 'Ùraich an dreuchd', + ], + 'delete_form' => [ + 'title' => 'Thoir {contributor} air falbh', + 'disclaimer' => + 'Tha thu an impis {contributor} a toirt air falbh on luchd-cuideachaidh. Chan urrainn dhaibh “{podcastTitle}” inntrigeadh tuilleadh an uairsin.', + 'understand' => 'Tha mi agaibh, tha mi airson {contributor} a thoirt air falbh o “{podcastTitle}”', + 'submit' => 'Thoir air falbh', + ], + 'messages' => [ + 'editSuccess' => 'Chaidh an dreuchd atharrachadh!', + 'editOwnerError' => "Chan urrainn dhut sealbhadair a’ phod-chraolaidh a dheasachadh!", + 'removeOwnerError' => "Chan urrainn dhut sealbhadair a’ phod-chraolaidh a thoirt air falbh!", + 'removeSuccess' => + 'Thug thu {username} air falbh o {podcastTitle}', + 'alreadyAddedError' => + "Chaidh an neach-cuideachaidh a tha thu airson cur ris a chur ris mu thràth!", + ], +]; diff --git a/modules/Auth/Language/gd/MyAccount.php b/modules/Auth/Language/gd/MyAccount.php new file mode 100644 index 00000000..1a9f8fe1 --- /dev/null +++ b/modules/Auth/Language/gd/MyAccount.php @@ -0,0 +1,18 @@ + 'Fiosrachadh a’ chunntais agam', + 'changePassword' => 'Atharraich am facal-faire agam', + 'messages' => [ + 'wrongPasswordError' => "Chuir thu a-steach am facal-faire ceàrr, feuch ris a-rithist.", + 'passwordChangeSuccess' => 'Chaidh am facal-faire atharrachadh!', + ], +]; diff --git a/modules/Auth/Language/gd/User.php b/modules/Auth/Language/gd/User.php new file mode 100644 index 00000000..33a1d513 --- /dev/null +++ b/modules/Auth/Language/gd/User.php @@ -0,0 +1,60 @@ + "Deasaich an dreuchd aig {username}", + 'ban' => 'Toirmisg', + 'unban' => 'Dì-thoirmisg', + 'delete' => 'Sguab às', + 'create' => 'Cleachdaiche ùr', + 'view' => "Am fiosrachadh aig {username}", + 'all_users' => 'A h-uile cleachdaiche', + 'list' => [ + 'user' => 'Cleachdaiche', + 'role' => 'Dreuchd', + 'banned' => 'Air a thoirmeasg?', + ], + 'form' => [ + 'email' => 'Post-d', + 'username' => 'Ainm-cleachdaiche', + 'password' => 'Facal-faire', + 'new_password' => 'Am facal-faire ùr', + 'role' => 'Dreuchd', + 'roles' => 'Dreuchdan', + 'permissions' => 'Ceadan', + 'submit_create' => 'Cruthaich cleachdaiche', + 'submit_edit' => 'Sàbhail', + 'submit_password_change' => 'Atharraich!', + ], + 'delete_form' => [ + 'title' => 'Sguab às {user}', + 'disclaimer' => + "Tha thu an impis {user} a sguabadh às gu buan. Chan urrainn dhaibh raon na rianachd inntrigeadh tuilleadh an uairsin.", + 'understand' => 'Tha mi agaibh, tha mi airson {user} a sguabadh às gu buan', + 'submit' => 'Sguab às', + ], + 'messages' => [ + 'createSuccess' => + 'Chaidh an cleachdaiche a chruthachadh! Chaidh post-d fàilteachaidh a chur gu {username} le ceangal clàraidh a-steach, thèid iarraidh orra gun ath-shuidhich iad am facal-faire aca a’ chiad turas a nì iad dearbhadh.', + 'roleEditSuccess' => + "Chaidh na dreuchdan aig {username} ùrachadh.", + 'banSuccess' => 'Chaidh {username} a thoirmeasg.', + 'unbanSuccess' => 'Chaidh {username} a dhì-thoirmeasg.', + 'editOwnerError' => + 'Is {username} sealbhadair an ionstans, na bean ris an t-sealbhadair…', + 'banSuperAdminError' => + 'Tha {username} ’na shàr-rianaire, na toirmisg sàr-rianaire…', + 'deleteOwnerError' => + 'Is {username} sealbhadair an ionstans, na sguab às an sealbhadair…', + 'deleteSuperAdminError' => + 'Tha {username} ’na shàr-rianaire, na sguab às sàr-rianaire…', + 'deleteSuccess' => 'Chaidh {username} a sguabadh às.', + ], +]; diff --git a/modules/Auth/Language/gl/Auth.php b/modules/Auth/Language/gl/Auth.php new file mode 100644 index 00000000..15902033 --- /dev/null +++ b/modules/Auth/Language/gl/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Propietaria da instancia', + 'description' => 'Propietaria de Castopod.', + ], + 'superadmin' => [ + 'title' => 'Super Admin', + 'description' => 'Ten control completo sobre Castopod.', + ], + 'manager' => [ + 'title' => 'Xestora', + 'description' => 'Quen xestiona o contido de Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Usuaria común de Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Pode acceder á área de administración.', + 'admin.settings' => 'Pode acceder aos axustes de Castopod.', + 'users.manage' => 'Pode xestionar as usuarias de Castopod.', + 'persons.manage' => 'Pode xestionar persoas.', + 'pages.manage' => 'Pode xestionar páxinas.', + 'podcasts.view' => 'Pode ver tódolos podcast.', + 'podcasts.create' => 'Pode crear novos podcast.', + 'podcasts.import' => 'Pode importar podcasts.', + 'fediverse.manage-blocks' => 'Pode bloquear actores/dominios do fediverso evitando interactuar con Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Dona do Podcast', + 'description' => 'A propietaria do podcast.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Ten control total sobre o podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editora', + 'description' => 'Persoa que xestiona o contido e publicacións do podcast #{id}.', + ], + 'author' => [ + 'title' => 'Autora', + 'description' => 'Persoa que xestiona o contido do podcast #{id} pero non pode publicalo.', + ], + 'guest' => [ + 'title' => 'Convidada', + 'description' => 'Contribuínte básico ao podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Pode ver o taboleiro e estatísticas do podcast #{id}.', + 'edit' => 'Pode editar o podcast #{id}.', + 'delete' => 'Pode eliminar o podcast #{id}.', + 'manage-import' => 'Pode sincronizar o podcast importado #{id}.', + 'manage-persons' => 'Pode xestionar as subscricións do podcast #{id}.', + 'manage-subscriptions' => 'Pode xestionar as subscricións do podcast #{id}.', + 'manage-contributors' => 'Pode xestionar as contribucións ao podcast #{id}.', + 'manage-platforms' => 'Pode establecer/eliminar ligazóns a plataformas do podcast #{id}.', + 'manage-publications' => 'Pode publicar o podcast #{id}.', + 'manage-notifications' => 'Pode ver e marcar as notificacións como lidas no podcast #{id}.', + 'interact-as' => 'Pode actuar como o podcast #{id} para compartir, favorecer ou responder a publicacións.', + 'episodes' => [ + 'view' => 'Pode ver os taboleiros e estatísticas dos episodios do podcast #{id}.', + 'create' => 'Pode crear episodios para o podcast #{id}.', + 'edit' => 'Pode editar os episodios do podcast #{id}.', + 'delete' => 'Pode eliminar episodios do podcast #{id}.', + 'manage-persons' => 'Pode xestionar as persoas do episodio do podcast #{id}.', + 'manage-clips' => 'Pode xestionar os clips de vídeo e extractos de audio do podcast #{id}.', + 'manage-publications' => 'Pode publicar/retirar episodios e publicacións do podcast #{id}.', + 'manage-comments' => 'Pode crear/eliminar comentarios dos episodios do podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Código de 6 díxitos', + + 'set_password' => 'Establece un contrasinal', + + // Welcome email + 'welcomeSubject' => 'Recibiches un convite para {siteName}', + 'emailWelcomeMailBody' => 'Creouse unha conta para ti en {domain}, preme na ligazón inferior de acceso para establecer un contrasinal. A ligazón é válida durante {numberOfHours} horas desde que se enviou este email.', +]; diff --git a/modules/Auth/Language/gl/Contributor.php b/modules/Auth/Language/gl/Contributor.php new file mode 100644 index 00000000..14dcf288 --- /dev/null +++ b/modules/Auth/Language/gl/Contributor.php @@ -0,0 +1,47 @@ + 'Contribúen ao podcast', + 'view' => "Contribución de {username} a {podcastTitle}", + 'add' => 'Engadir colaboración', + 'add_contributor' => 'Engadir unha colaboración a {0}', + 'edit_role' => 'Actualizar rol de {0}', + 'edit' => 'Editar', + 'remove' => 'Eliminar', + 'list' => [ + 'username' => 'Identificador', + 'role' => 'Rol', + ], + 'form' => [ + 'user' => 'Usuaria', + 'user_placeholder' => 'Elixe unha usuaria…', + 'role' => 'Rol', + 'role_placeholder' => 'Elixe o seu rol…', + 'submit_add' => 'Engadir colaboración', + 'submit_edit' => 'Actualizar rol', + ], + 'delete_form' => [ + 'title' => 'Eliminar {contributor}', + 'disclaimer' => + 'Vas a eliminar a {contributor} de entre as contribuíntes. Non poderá volver acceder a "{podcastTitle}".', + 'understand' => 'Enténdoo, quero eliminar a {contributor} de "{podcastTitle}"', + 'submit' => 'Eliminar', + ], + 'messages' => [ + 'editSuccess' => 'Rol cambiado correctamente!', + 'editOwnerError' => "Non podes editar a propietaria do podcast!", + 'removeOwnerError' => "Non podes eliminar a propietaria do podcast!", + 'removeSuccess' => + 'Quitaches correctamente a {username} de {podcastTitle}', + 'alreadyAddedError' => + "A colaboradora que intentas engadir xa está engadida!", + ], +]; diff --git a/modules/Auth/Language/gl/MyAccount.php b/modules/Auth/Language/gl/MyAccount.php new file mode 100644 index 00000000..43b1e470 --- /dev/null +++ b/modules/Auth/Language/gl/MyAccount.php @@ -0,0 +1,18 @@ + 'Info da miña conta', + 'changePassword' => 'Cambiar o meu contrasinal', + 'messages' => [ + 'wrongPasswordError' => "Escribiches un contrasinal incorrecto, volve a intentalo.", + 'passwordChangeSuccess' => 'Cambiaches correctamente o contrasinal!', + ], +]; diff --git a/modules/Auth/Language/gl/User.php b/modules/Auth/Language/gl/User.php new file mode 100644 index 00000000..668d56a5 --- /dev/null +++ b/modules/Auth/Language/gl/User.php @@ -0,0 +1,60 @@ + "Editar os roles de {username}", + 'ban' => 'Vetar', + 'unban' => 'Retirar veto', + 'delete' => 'Eliminar', + 'create' => 'Nova usuaria', + 'view' => "Info de {username}", + 'all_users' => 'Tódalas usuarias', + 'list' => [ + 'user' => 'Usuaria', + 'role' => 'Rol', + 'banned' => 'Vetada?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Identificador', + 'password' => 'Contrasinal', + 'new_password' => 'Novo contrasinal', + 'role' => 'Rol', + 'roles' => 'Roles', + 'permissions' => 'Permisos', + 'submit_create' => 'Crear usuaria', + 'submit_edit' => 'Gardar', + 'submit_password_change' => 'Cambiar!', + ], + 'delete_form' => [ + 'title' => 'Eliminar {user}', + 'disclaimer' => + "Vas eliminar de xeito permanente a {user}. Non poderá volver a acceder á páxina de administración.", + 'understand' => 'Enténdoo, quero eliminar a {user} para sempre', + 'submit' => 'Eliminar', + ], + 'messages' => [ + 'createSuccess' => + 'Usuaria creada correctamente! Váiselle pedir a {username} que cambie o seu contrasinal após o primeiro acceso.', + 'roleEditSuccess' => + "Os roles de {username} actualizáronse correctamente.", + 'banSuccess' => '{username} foi vetada.', + 'unbanSuccess' => 'Retirouse o veto sobre {username}.', + 'editOwnerError' => + 'A instancia pertence a {username}, ti non podes editar os roles.', + 'banSuperAdminError' => + '{username} é superadmin, non se pode vetar a superadmin…', + 'deleteOwnerError' => + '{username} é dona da instancia, non se pode eliminar a propietaria…', + 'deleteSuperAdminError' => + '{username} é superadmin, non se pode eliminar a superadmin…', + 'deleteSuccess' => 'Eliminouse a {username}.', + ], +]; diff --git a/modules/Auth/Language/id/Auth.php b/modules/Auth/Language/id/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/id/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/id/Contributor.php b/modules/Auth/Language/id/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/id/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/id/MyAccount.php b/modules/Auth/Language/id/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/id/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/id/User.php b/modules/Auth/Language/id/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/id/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/it/Auth.php b/modules/Auth/Language/it/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/it/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/it/Contributor.php b/modules/Auth/Language/it/Contributor.php new file mode 100644 index 00000000..b82b51bb --- /dev/null +++ b/modules/Auth/Language/it/Contributor.php @@ -0,0 +1,47 @@ + 'Collaboratori del podcast', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Aggiungi collaboratore', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Modifica', + 'remove' => 'Rimuovi', + 'list' => [ + 'username' => 'Nome Utente', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Seleziona un utente…', + 'role' => 'Ruolo', + 'role_placeholder' => 'Seleziona il suo ruolo…', + 'submit_add' => 'Aggiungi collaboratore', + 'submit_edit' => 'Aggiorna Ruolo', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "Non puoi rimuovere il proprietario del podcast!", + 'removeSuccess' => + 'Hai rimosso con successo {username} da {podcastTitle}', + 'alreadyAddedError' => + "Il collaboratore che stai cercando di aggiungere è già stato aggiunto!", + ], +]; diff --git a/modules/Auth/Language/it/MyAccount.php b/modules/Auth/Language/it/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/it/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/it/User.php b/modules/Auth/Language/it/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/it/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/ja/Auth.php b/modules/Auth/Language/ja/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/ja/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/ja/Contributor.php b/modules/Auth/Language/ja/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/ja/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/ja/MyAccount.php b/modules/Auth/Language/ja/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/ja/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/ja/User.php b/modules/Auth/Language/ja/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/ja/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/kk/Auth.php b/modules/Auth/Language/kk/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/kk/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/kk/Contributor.php b/modules/Auth/Language/kk/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/kk/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/kk/MyAccount.php b/modules/Auth/Language/kk/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/kk/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/kk/User.php b/modules/Auth/Language/kk/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/kk/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/ko/Auth.php b/modules/Auth/Language/ko/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/ko/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/ko/Contributor.php b/modules/Auth/Language/ko/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/ko/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/ko/MyAccount.php b/modules/Auth/Language/ko/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/ko/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/ko/User.php b/modules/Auth/Language/ko/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/ko/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/nl/Auth.php b/modules/Auth/Language/nl/Auth.php new file mode 100644 index 00000000..31521984 --- /dev/null +++ b/modules/Auth/Language/nl/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance eigenaar', + 'description' => 'De Castopod eigenaar.', + ], + 'superadmin' => [ + 'title' => 'Super beheerder', + 'description' => 'Heeft de volledige controle over Castopod.', + ], + 'manager' => [ + 'title' => 'Beheerder', + 'description' => 'Beheert de inhoud van Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Algemene gebruikers van Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Kan toegang krijgen tot de beheeromgeving van Castopod.', + 'admin.settings' => 'Kan toegang krijgen tot de instellingen van Castopod.', + 'users.manage' => 'Kan Castopod-gebruikers beheren.', + 'persons.manage' => 'Kan personen beheren.', + 'pages.manage' => 'Kan pagina\'s beheren.', + 'podcasts.view' => 'Kan alle podcasts bekijken.', + 'podcasts.create' => 'Kan nieuwe podcast aanmaken.', + 'podcasts.import' => 'Kan podcasts importeren.', + 'fediverse.manage-blocks' => 'Kan fediverse actors/domains blokkeren voor interactie met Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Eigenaar', + 'description' => 'De eigenaar van de podcast.', + ], + 'admin' => [ + 'title' => 'Beheerder', + 'description' => 'Heeft de volledige controle over podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Redacteur', + 'description' => 'Beheert inhoud en publicaties van podcast #{id}.', + ], + 'author' => [ + 'title' => 'Auteur', + 'description' => 'Beheert de inhoud van podcast #{id} maar kan deze niet publiceren.', + ], + 'guest' => [ + 'title' => 'Gast', + 'description' => 'Algemene bijdrager van podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Kan dashboard en analyses van podcast #{id} zien.', + 'edit' => 'Kan podcast #{id} wijzigen.', + 'delete' => 'Kan podcast #{id} verwijderen.', + 'manage-import' => 'Kan de geïmporteerde podcast #{id} synchroniseren.', + 'manage-persons' => 'Kan abonnementen van podcast #{id} beheren.', + 'manage-subscriptions' => 'Kan abonnementen van podcast #{id} beheren.', + 'manage-contributors' => 'Kan bijdragers van podcast #{id} beheren.', + 'manage-platforms' => 'Kan platform links van podcast #{id} instellen of verwijderen.', + 'manage-publications' => 'Kan podcast #{id} publiceren.', + 'manage-notifications' => 'Kan meldingen bekijken en markeren als gelezen voor podcast #{id}.', + 'interact-as' => 'Kan als podcast #{id} handelen om te favorieten, te delen of te reageren op berichten.', + 'episodes' => [ + 'view' => 'Kan dashboard en analyses van de afleveringen van podcast #{id} zien.', + 'create' => 'Kan afleveringen voor podcast #{id} aanmaken.', + 'edit' => 'Kan afleveringen van podcast #{id} wijzigen.', + 'delete' => 'Kan afleveringen van podcast #{id} verwijderen.', + 'manage-persons' => 'Kan aflevering personen van podcast #{id} beheren.', + 'manage-clips' => 'Kan videoclips of soundbites van podcast #{id} beheren.', + 'manage-publications' => 'Kan afleveringen en berichten van podcast #{id} publiceren/depubliceren.', + 'manage-comments' => 'Kan opmerkingen van aflevering van podcast van #{id} maken of verwijderen.', + ], + ], + + // missing keys + 'code' => 'Jouw 6-cijferige code', + + 'set_password' => 'Stel je wachtwoord in', + + // Welcome email + 'welcomeSubject' => 'Je bent uitgenodigd voor {siteName}', + 'emailWelcomeMailBody' => 'Er is een account voor u aangemaakt op {domain}, klik op onderstaande inloglink om uw wachtwoord in te stellen. De link is geldig tot {numberOfHours} uur nadat deze e-mail is verzonden.', +]; diff --git a/modules/Auth/Language/nl/Contributor.php b/modules/Auth/Language/nl/Contributor.php new file mode 100644 index 00000000..f6b11364 --- /dev/null +++ b/modules/Auth/Language/nl/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast bijdragers', + 'view' => "Bijdrage van {username} aan {podcastTitle}", + 'add' => 'Voeg bijdrager toe', + 'add_contributor' => 'Voeg een bijdrager toe voor {0}', + 'edit_role' => 'Rol bijwerken voor {0}', + 'edit' => 'Bewerken', + 'remove' => 'Verwijder', + 'list' => [ + 'username' => 'Gebruikersnaam', + 'role' => 'Rol', + ], + 'form' => [ + 'user' => 'Gebruiker', + 'user_placeholder' => 'Selecteer een gebruiker…', + 'role' => 'Rol', + 'role_placeholder' => 'Selecteer de rol…', + 'submit_add' => 'Voeg bijdrager toe', + 'submit_edit' => 'Rol bijwerken', + ], + 'delete_form' => [ + 'title' => 'Verwijder {contributor}', + 'disclaimer' => + 'Je staat op het punt {contributor} te verwijderen van bijdragers. Ze zullen geen toegang meer hebben tot "{podcastTitle}".', + 'understand' => 'Ik begrijp het, ik wil {contributor} verwijderen van "{podcastTitle}"', + 'submit' => 'Verwijder', + ], + 'messages' => [ + 'editSuccess' => 'Rol succesvol veranderd!', + 'editOwnerError' => "Je kunt de eigenaar van podcast niet bewerken!", + 'removeOwnerError' => "Je kunt de eigenaar van podcast niet verwijderen!", + 'removeSuccess' => + 'Je hebt {username} met succes verwijderd van {podcastTitle}', + 'alreadyAddedError' => + "De bijdrager die je probeert toe te voegen, is al toegevoegd!", + ], +]; diff --git a/modules/Auth/Language/nl/MyAccount.php b/modules/Auth/Language/nl/MyAccount.php new file mode 100644 index 00000000..c7a5d5cf --- /dev/null +++ b/modules/Auth/Language/nl/MyAccount.php @@ -0,0 +1,18 @@ + 'Mijn accountgegevens', + 'changePassword' => 'Wijzig mijn wachtwoord', + 'messages' => [ + 'wrongPasswordError' => "Je hebt een verkeerd wachtwoord ingevoerd, probeer het opnieuw.", + 'passwordChangeSuccess' => 'Wachtwoord is succesvol gewijzigd!', + ], +]; diff --git a/modules/Auth/Language/nl/User.php b/modules/Auth/Language/nl/User.php new file mode 100644 index 00000000..ee321721 --- /dev/null +++ b/modules/Auth/Language/nl/User.php @@ -0,0 +1,60 @@ + "Rol van {username} wijzigen", + 'ban' => 'Blokkeren', + 'unban' => 'Deblokkeren', + 'delete' => 'Verwijderen', + 'create' => 'Nieuwe gebruiker', + 'view' => "Info van {username}", + 'all_users' => 'Alle gebruikers', + 'list' => [ + 'user' => 'Gebruiker', + 'role' => 'Rol', + 'banned' => 'Geblokkeerd?', + ], + 'form' => [ + 'email' => 'E-mail', + 'username' => 'Gebruikersnaam', + 'password' => 'Wachtwoord', + 'new_password' => 'Nieuw Wachtwoord', + 'role' => 'Rol', + 'roles' => 'Rollen', + 'permissions' => 'Rechten', + 'submit_create' => 'Gebruiker aanmaken', + 'submit_edit' => 'Opslaan', + 'submit_password_change' => 'Wijzigen!', + ], + 'delete_form' => [ + 'title' => 'Verwijder {user}', + 'disclaimer' => + "Je staat op het punt {user} permanent te verwijderen. Deze zal geen toegang meer hebben tot de beheerdersomgeving.", + 'understand' => 'Ik begrijp het, ik wil {user} permanent verwijderen', + 'submit' => 'Verwijderen', + ], + 'messages' => [ + 'createSuccess' => + 'Gebruiker succesvol aangemaakt! Een welkomsmail is naar {username} verzonden met een inloglink, bij de eerste authenticatie zal er om een wachtwoordreset gevraagd worden.', + 'roleEditSuccess' => + "De rollen van {username} zijn succesvol bijgewerkt.", + 'banSuccess' => '{username} is geblokkeerd.', + 'unbanSuccess' => '{username} is gedeblokkeerd.', + 'editOwnerError' => + '{username} is de instance eigenaar, men raakt niet zomaar de eigenaar aan…', + 'banSuperAdminError' => + '{username} is een super beheerder, men raakt niet zomaar een super beheerder aan…', + 'deleteOwnerError' => + '{username} is de instance eigenaar, men verwijderd niet zomaar de eigenaar…', + 'deleteSuperAdminError' => + '{username} is een superadmin, men verwijderd niet zomaar een superadmin…', + 'deleteSuccess' => '{username} is verwijderd.', + ], +]; diff --git a/modules/Auth/Language/nn-no/Auth.php b/modules/Auth/Language/nn-no/Auth.php new file mode 100644 index 00000000..ba1c57f9 --- /dev/null +++ b/modules/Auth/Language/nn-no/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Nettstadeigar', + 'description' => 'Castopod-eigaren.', + ], + 'superadmin' => [ + 'title' => 'Superstyrar', + 'description' => 'Har full kontroll over Castopod.', + ], + 'manager' => [ + 'title' => 'Leiar', + 'description' => 'Styrer innhaldet på Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podkastar', + 'description' => 'Vanlege Castopod-brukarar.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Kan bruka styringspanelet for Castopod.', + 'admin.settings' => 'Kan få tilgang til innstillingane for Castopod.', + 'users.manage' => 'Kan handtera Castopod-brukarar.', + 'persons.manage' => 'Kan handtera folk.', + 'pages.manage' => 'Kan handtera sider.', + 'podcasts.view' => 'Kan sjå alle podkastane.', + 'podcasts.create' => 'Kan laga nye podkastar.', + 'podcasts.import' => 'Kan importera podkastar.', + 'fediverse.manage-blocks' => 'Kan blokkera folk og domene på allheimen frå å samhandla med Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podkasteigar', + 'description' => 'Podkasteigaren.', + ], + 'admin' => [ + 'title' => 'Administrator', + 'description' => 'Har full kontroll over podkasten #{id}.', + ], + 'editor' => [ + 'title' => 'Redaktør', + 'description' => 'Styrer innhald og publisering for podkasten #{id}.', + ], + 'author' => [ + 'title' => 'Skapar', + 'description' => 'Styrer innhald for podkasten #{id}, men kan ikkje publisera dei.', + ], + 'guest' => [ + 'title' => 'Gjest', + 'description' => 'Vanleg bidragsytar til podkasten #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Kan sjå styringspanelet og analysedata for podkasten #{id}.', + 'edit' => 'Kan redigera podkasten #{id}.', + 'delete' => 'Kan sletta podkasten #{id}.', + 'manage-import' => 'Kan synkronisera den importerte podkasten #{id}.', + 'manage-persons' => 'Kan handtera abonnement for podkasten #{id}.', + 'manage-subscriptions' => 'Kan handtera abonnement for podkasten #{id}.', + 'manage-contributors' => 'Kan handtera bidragsytarar for podkasten #{id}.', + 'manage-platforms' => 'Kan oppretta og fjerna plattformlenkjer for podkasten #{id}.', + 'manage-publications' => 'Kan publisera podkasten #{id}.', + 'manage-notifications' => 'Kan lesa og merka varsel som lesne for podkasten #{id}.', + 'interact-as' => 'Kan merka podkasten #{id} som favoritt, dela og svara på innlegg.', + 'episodes' => [ + 'view' => 'Kan sjå styringspanelet og analysedata for episodane av podkasten #{id}.', + 'create' => 'Kan laga epoisodar for podkasten #{id}.', + 'edit' => 'Kan redigera episodane av podkasten #{id}.', + 'delete' => 'Kan sletta episodar av podkasten #{id}.', + 'manage-persons' => 'Kan handtera bidragsytarar til episodar av podkasten #{id}.', + 'manage-clips' => 'Kan handtera film- og lydklypp av podkasten #{id}.', + 'manage-publications' => 'Kan publisera og avpublisera episodar og innlegg for podkasten #{id}.', + 'manage-comments' => 'Kan skriva og sletta kommentarar til episodane av podkasten #{id}.', + ], + ], + + // missing keys + 'code' => 'Den sekssifra koden din', + + 'set_password' => 'Lag eit passord', + + // Welcome email + 'welcomeSubject' => 'Du er invitert til {siteName}', + 'emailWelcomeMailBody' => 'Me har laga ein konto til deg på {domain}. Klikk på lenka under for å laga eit passord. Lenka er gyldig i {numberOfHours} timar etter eposten vart send.', +]; diff --git a/modules/Auth/Language/nn-no/Contributor.php b/modules/Auth/Language/nn-no/Contributor.php new file mode 100644 index 00000000..941af518 --- /dev/null +++ b/modules/Auth/Language/nn-no/Contributor.php @@ -0,0 +1,47 @@ + 'Podkast-bidragsytarar', + 'view' => "{username} sitt bidrag til {podcastTitle}", + 'add' => 'Legg til bidragsytar', + 'add_contributor' => 'Legg til bidragsytar til {0}', + 'edit_role' => 'Oppdater rolla for {0}', + 'edit' => 'Rediger', + 'remove' => 'Fjern', + 'list' => [ + 'username' => 'Brukarnamn', + 'role' => 'Rolle', + ], + 'form' => [ + 'user' => 'Brukar', + 'user_placeholder' => 'Vel ein brukar…', + 'role' => 'Rolle', + 'role_placeholder' => 'Vel rolle…', + 'submit_add' => 'Legg til bidragsytar', + 'submit_edit' => 'Oppdater rolla', + ], + 'delete_form' => [ + 'title' => 'Fjern {contributor}', + 'disclaimer' => + 'Du er i ferd med å fjerna {contributor} som bidragsytar. Dei vil mista tilgangen til "{podcastTitle}".', + 'understand' => 'Eg forstår, og vil fjerna {contributor} frå "{podcastTitle}"', + 'submit' => 'Fjern', + ], + 'messages' => [ + 'editSuccess' => 'Rolle endra!', + 'editOwnerError' => "Du kan ikkje endra podkast-eigaren.", + 'removeOwnerError' => "Du kan ikkje fjerna podkast-eigaren!", + 'removeSuccess' => + 'Du har fjerna {username} frå {podcastTitle}', + 'alreadyAddedError' => + "Denne bidragsytaren er allereie lagt til!", + ], +]; diff --git a/modules/Auth/Language/nn-no/MyAccount.php b/modules/Auth/Language/nn-no/MyAccount.php new file mode 100644 index 00000000..a853dc8a --- /dev/null +++ b/modules/Auth/Language/nn-no/MyAccount.php @@ -0,0 +1,18 @@ + 'Kontoinformasjonen min', + 'changePassword' => 'Endra passordet mitt', + 'messages' => [ + 'wrongPasswordError' => "Du skreiv inn feil passord. Prøv ein gong til.", + 'passwordChangeSuccess' => 'Passordet er endra!', + ], +]; diff --git a/modules/Auth/Language/nn-no/User.php b/modules/Auth/Language/nn-no/User.php new file mode 100644 index 00000000..fedf303b --- /dev/null +++ b/modules/Auth/Language/nn-no/User.php @@ -0,0 +1,60 @@ + "Endre rollene til {username}", + 'ban' => 'Steng ute', + 'unban' => 'Slepp inn att', + 'delete' => 'Slett', + 'create' => 'Ny brukar', + 'view' => "{username} sin informasjon", + 'all_users' => 'Alle brukarane', + 'list' => [ + 'user' => 'Brukar', + 'role' => 'Rolle', + 'banned' => 'Utestengd?', + ], + 'form' => [ + 'email' => 'Epost', + 'username' => 'Brukarnamn', + 'password' => 'Passord', + 'new_password' => 'Nytt passord', + 'role' => 'Rolle', + 'roles' => 'Roller', + 'permissions' => 'Løyve', + 'submit_create' => 'Lag brukar', + 'submit_edit' => 'Lagre', + 'submit_password_change' => 'Endre!', + ], + 'delete_form' => [ + 'title' => 'Slett {user}', + 'disclaimer' => + "Du er i ferd med å sletta {user} for alltid. Dei vil ikkje få tilgang til styringspanelet lenger.", + 'understand' => 'Eg forstår, og vil sletta {user} for alltid', + 'submit' => 'Slett', + ], + 'messages' => [ + 'createSuccess' => + 'Brukaren er oppretta! {username} vil få spørsmål om å endra passord fyrste gong hen loggar inn.', + 'roleEditSuccess' => + "Rollene til {username} er oppdaterte.", + 'banSuccess' => '{username} er utestengd.', + 'unbanSuccess' => '{username} fekk sleppa inn att.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} er superstyrar, og du stengjer ikkje ute ein superstyrar…', + 'deleteOwnerError' => + '{username} eig nettstaden. Du kan ikkje berre sletta eigaren…', + 'deleteSuperAdminError' => + '{username} er superstyrar, og du slettar ikkje ein superstyrar…', + 'deleteSuccess' => '{username} er sletta.', + ], +]; diff --git a/modules/Auth/Language/oc/Auth.php b/modules/Auth/Language/oc/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/oc/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/oc/Contributor.php b/modules/Auth/Language/oc/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/oc/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/oc/MyAccount.php b/modules/Auth/Language/oc/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/oc/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/oc/User.php b/modules/Auth/Language/oc/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/oc/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/pl/Auth.php b/modules/Auth/Language/pl/Auth.php new file mode 100644 index 00000000..bbc42f95 --- /dev/null +++ b/modules/Auth/Language/pl/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Właściciel instancji', + 'description' => 'Właściciel Castopoda.', + ], + 'superadmin' => [ + 'title' => 'Superadministrator', + 'description' => 'Ma pełną kontrolę nad Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Zarządza zawartością Castopoda.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Zwykli użytkownicy Castopoda.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Ma dostęp do panelu administracyjnego Castopoda.', + 'admin.settings' => 'Ma dostęp do ustawień Castopoda.', + 'users.manage' => 'Może zarządzać użytkownikami Castopoda.', + 'persons.manage' => 'Może zarządzać osobami.', + 'pages.manage' => 'Może zarządzać stronami.', + 'podcasts.view' => 'Może wyświetlać wszystkie podcasty.', + 'podcasts.create' => 'Może tworzyć nowe podcasty.', + 'podcasts.import' => 'Może importować podcasty.', + 'fediverse.manage-blocks' => 'Można blokować aktorów/domeny z fediwersum przed interakcjami z Castopodem.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Właściciel Podcastu', + 'description' => 'Właściciel podcastu.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Ma pełną kontrolę nad podcastem #{id}.', + ], + 'editor' => [ + 'title' => 'Edytor', + 'description' => 'Zarządza treścią i publikacjami podcastu #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Zarządza zawartością podcastu #{id}, ale nie może jej opublikować.', + ], + 'guest' => [ + 'title' => 'Gość', + 'description' => 'Główny współtwórca podcastu #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Może wyświetlań panel zarządzania oraz analitykę podcastu #{id}.', + 'edit' => 'Może edytować podcast #{id}.', + 'delete' => 'Może usunąć podcast #{id}.', + 'manage-import' => 'Może synchronizować importowany podcast #{id}.', + 'manage-persons' => 'Może zarządzać subskrypcjami podcastu #{id}.', + 'manage-subscriptions' => 'Może zarządzać subskrypcjami podcastu #{id}.', + 'manage-contributors' => 'Może zarządzać współtwórcami podcastu #{id}.', + 'manage-platforms' => 'Można ustawić/usunąć linki platformy podcastu #{id}.', + 'manage-publications' => 'Może publikować podcast #{id}.', + 'manage-notifications' => 'Może wyświetlać i oznaczać powiadomienia jako przeczytane dla podcastu #{id}.', + 'interact-as' => 'Może jako podcast #{id} dodawać do ulubionych, udostępniać lub odpowiadać na posty.', + 'episodes' => [ + 'view' => 'Może wyświetlać panel zarządzania oraz analitykę odcinków podcastu #{id}.', + 'create' => 'Może tworzyć odcinki dla podcastu #{id}.', + 'edit' => 'Może edytować odcinki podcastu #{id}.', + 'delete' => 'Można usuwać odcinki podcastu #{id}.', + 'manage-persons' => 'Może zarządzać osobami w odcinkach podcastu #{id}.', + 'manage-clips' => 'Może zarządzać klipami wideo lub zajawkami podcastu #{id}.', + 'manage-publications' => 'Może publikować/cofać publikowanie odcinków i postów podcastu #{id}.', + 'manage-comments' => 'Może tworzyć/usuwać komentarze odcinka podcastu #{id}.', + ], + ], + + // missing keys + 'code' => 'Twój 6-cyfrowy kod', + + 'set_password' => 'Ustaw swoje hasło', + + // Welcome email + 'welcomeSubject' => 'Zostałeś zaproszony do {siteName}', + 'emailWelcomeMailBody' => 'Na {domain} zostało utworzone dla Ciebie konto, kliknij poniższy link logowania, aby ustawić hasło. Link jest ważny przez {numberOfHours} godzin po wysłaniu tego e-maila.', +]; diff --git a/modules/Auth/Language/pl/Contributor.php b/modules/Auth/Language/pl/Contributor.php new file mode 100644 index 00000000..0a5515d1 --- /dev/null +++ b/modules/Auth/Language/pl/Contributor.php @@ -0,0 +1,47 @@ + 'Kontrybutorzy podcastu', + 'view' => "Wkład {username} do {podcastTitle}", + 'add' => 'Dodaj kontrybutora', + 'add_contributor' => 'Dodaj kontrybutora do {0}', + 'edit_role' => 'Zaktualizuj rolę dla {0}', + 'edit' => 'Edytuj', + 'remove' => 'Usuń', + 'list' => [ + 'username' => 'Nazwa użytkownika', + 'role' => 'Rola', + ], + 'form' => [ + 'user' => 'Użytkownik', + 'user_placeholder' => 'Wybierz użytkownika…', + 'role' => 'Rola', + 'role_placeholder' => 'Wybierz jego rolę…', + 'submit_add' => 'Dodaj kontrybutora', + 'submit_edit' => 'Zaktualizuj rolę', + ], + 'delete_form' => [ + 'title' => 'Usuń {contributor}', + 'disclaimer' => + 'Zamierzasz usunąć {contributor} z wspierających. Nie będzie miał już mieć dostępu do "{podcastTitle}".', + 'understand' => 'Rozumiem, chcę usunąć {contributor} z "{podcastTitle}"', + 'submit' => 'Usuń', + ], + 'messages' => [ + 'editSuccess' => 'Pomyślnie zmieniono rolę!', + 'editOwnerError' => "Nie możesz edytować właściciela podcastu!", + 'removeOwnerError' => "Nie możesz usunąć właściciela podcastu!", + 'removeSuccess' => + 'Pomyślnie usunąłeś/aś {username} z {podcastTitle}', + 'alreadyAddedError' => + "Kontrybutor, którego próbujesz dodać, został już dodany!", + ], +]; diff --git a/modules/Auth/Language/pl/MyAccount.php b/modules/Auth/Language/pl/MyAccount.php new file mode 100644 index 00000000..3b27b7fe --- /dev/null +++ b/modules/Auth/Language/pl/MyAccount.php @@ -0,0 +1,18 @@ + 'Informacje o moim koncie', + 'changePassword' => 'Zmień moje hasło', + 'messages' => [ + 'wrongPasswordError' => "Wpisałeś złe hasło, spróbuj ponownie.", + 'passwordChangeSuccess' => 'Hasło zostało pomyślnie zmienione!', + ], +]; diff --git a/modules/Auth/Language/pl/User.php b/modules/Auth/Language/pl/User.php new file mode 100644 index 00000000..69f2d96b --- /dev/null +++ b/modules/Auth/Language/pl/User.php @@ -0,0 +1,60 @@ + "Edytuj role użytkownika {username}", + 'ban' => 'Zablokuj', + 'unban' => 'Odblokuj', + 'delete' => 'Usuń', + 'create' => 'Nowy użytkownik', + 'view' => "Informacje użytkownika {username}", + 'all_users' => 'Wszyscy użytkownicy', + 'list' => [ + 'user' => 'Użytkownik', + 'role' => 'Rola', + 'banned' => 'Zablokowany?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Nazwa użytkownika', + 'password' => 'Hasło', + 'new_password' => 'Nowe hasło', + 'role' => 'Rola', + 'roles' => 'Role', + 'permissions' => 'Uprawnienia', + 'submit_create' => 'Stwórz użytkownika', + 'submit_edit' => 'Zapisz', + 'submit_password_change' => 'Zmień!', + ], + 'delete_form' => [ + 'title' => 'Usuń użytkownika {user}', + 'disclaimer' => + "Zamierzasz usunąć {user} na stałe. Nie będą już mogli uzyskać dostępu do obszaru administratora.", + 'understand' => 'Rozumiem, chcę trwale usunąć {user}', + 'submit' => 'Usuń', + ], + 'messages' => [ + 'createSuccess' => + 'Pomyślnie utworzono użytkownika! {username} zostanie poproszony o zresetowanie hasła przy pierwszym uwierzytelnieniu.', + 'roleEditSuccess' => + "Role {username} zostały pomyślnie zaktualizowane.", + 'banSuccess' => '{username} został zablokowany.', + 'unbanSuccess' => '{username} został odblokowany.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} jest superadministratorem, nie można po prostu zablokować superadministratora…', + 'deleteOwnerError' => + '{username} jest właścicielem instancji, nie można usunąć właściciela…', + 'deleteSuperAdminError' => + '{username} jest superadministratorem, nie można po prostu usunąć superadministratora…', + 'deleteSuccess' => '{username} został usunięty.', + ], +]; diff --git a/modules/Auth/Language/pt-br/Auth.php b/modules/Auth/Language/pt-br/Auth.php new file mode 100644 index 00000000..2637625b --- /dev/null +++ b/modules/Auth/Language/pt-br/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instância proprietário', + 'description' => 'O proprietário do Castopod.', + ], + 'superadmin' => [ + 'title' => 'Super administrador', + 'description' => 'Tem controle completo sobre Castopod.', + ], + 'manager' => [ + 'title' => 'Gerente', + 'description' => 'Gerencia o conteúdo de Castopod.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Usuários gerais do Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Pode acessar a área de administração do Castopod.', + 'admin.settings' => 'Pode acessar as configurações de Castopod.', + 'users.manage' => 'Pode gerenciar usuários do Castopod.', + 'persons.manage' => 'Pode gerenciar pessoas.', + 'pages.manage' => 'Pode gerenciar páginas.', + 'podcasts.view' => 'Pode ver todos os podcasts.', + 'podcasts.create' => 'Pode criar novos podcasts.', + 'podcasts.import' => 'Pode importar podcasts.', + 'fediverse.manage-blocks' => 'Pode bloquear ator/domínios distintos de interagir com Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Dono do Podcast', + 'description' => 'O proprietário do podcast.', + ], + 'admin' => [ + 'title' => 'Administrador', + 'description' => 'Tem controle completo do podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Gerencia o conteúdo e as publicações do podcast #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Gerencia o conteúdo do podcast #{id} mas não pode publicá-los.', + ], + 'guest' => [ + 'title' => 'Convidado', + 'description' => 'Contribuidor geral do podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Pode visualizar o painel de controle e análises do podcast #{id}.', + 'edit' => 'Pode editar o podcast #{id}.', + 'delete' => 'Pode deletar episódios do podcast #{id}.', + 'manage-import' => 'Pode sincronizar o podcast importado #{id}.', + 'manage-persons' => 'Pode gerenciar assinaturas do podcast #{id}.', + 'manage-subscriptions' => 'Pode gerenciar assinaturas do podcast #{id}.', + 'manage-contributors' => 'Pode gerenciar contribuidores do podcast #{id}.', + 'manage-platforms' => 'Pode definir/remover links de plataforma do podcast #{id}.', + 'manage-publications' => 'Pode publicar podcast #{id}.', + 'manage-notifications' => 'Pode ver e marcar notificações como lidas para o podcast #{id}.', + 'interact-as' => 'Pode interagir com o podcast #{id} para favorito, compartilhar ou responder às publicações.', + 'episodes' => [ + 'view' => 'Pode ver painéis e análises de episódios de podcast #{id}.', + 'create' => 'Pode criar episódios para o podcast #{id}.', + 'edit' => 'Pode editar episódios de podcast #{id}.', + 'delete' => 'Pode excluir episódios do podcast #{id}.', + 'manage-persons' => 'Pode gerenciar pessoas de episódios do podcast #{id}.', + 'manage-clips' => 'Pode gerenciar clipes de vídeo ou sons de episódios do podcast #{id}.', + 'manage-publications' => 'Pode publicar/remover a publicação de episódios e postagens de podcast #{id}.', + 'manage-comments' => 'Pode criar/remover comentários de episódio do podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Seu código de 6 dígitos', + + 'set_password' => 'Defina sua senha', + + // Welcome email + 'welcomeSubject' => 'Você foi convidado(a) para o {siteName}', + 'emailWelcomeMailBody' => 'Uma conta foi criada para você no {domain}, clique no link de login abaixo para definir sua senha. O link é válido por {numberOfHours} horas após o envio deste e-mail.', +]; diff --git a/modules/Auth/Language/pt-br/Contributor.php b/modules/Auth/Language/pt-br/Contributor.php new file mode 100644 index 00000000..5dc72942 --- /dev/null +++ b/modules/Auth/Language/pt-br/Contributor.php @@ -0,0 +1,47 @@ + 'Contribuidores do Podcast', + 'view' => "Contribuição de {username} para {podcastTitle}", + 'add' => 'Adicionar contribuidor', + 'add_contributor' => 'Adicionar um contribuidor para {0}', + 'edit_role' => 'Atualizar cargo para {0}', + 'edit' => 'Editar', + 'remove' => 'Remover', + 'list' => [ + 'username' => 'Nome de usuário', + 'role' => 'Cargo', + ], + 'form' => [ + 'user' => 'Usuário', + 'user_placeholder' => 'Selecione um usuário…', + 'role' => 'Cargo', + 'role_placeholder' => 'Selecione seu cargo…', + 'submit_add' => 'Adicionar contribuidor', + 'submit_edit' => 'Atualizar cargo', + ], + 'delete_form' => [ + 'title' => 'Remover {contributor}', + 'disclaimer' => + 'Você está prestes a remover {contributor} dos colaboradores. Eles não poderão mais acessar "{podcastTitle}".', + 'understand' => 'Eu entendo, eu desejo remover {contributor} de "{podcastTitle}"', + 'submit' => 'Remover', + ], + 'messages' => [ + 'editSuccess' => 'Cargo alterado com sucesso!', + 'editOwnerError' => "Você não pode editar o dono do podcast!", + 'removeOwnerError' => "Você não pode remover o dono do podcast!", + 'removeSuccess' => + 'Você removeu {username} com sucesso de {podcastTitle}', + 'alreadyAddedError' => + "O contribuidor que você está tentando adicionar já foi adicionado!", + ], +]; diff --git a/modules/Auth/Language/pt-br/MyAccount.php b/modules/Auth/Language/pt-br/MyAccount.php new file mode 100644 index 00000000..5c24c2f1 --- /dev/null +++ b/modules/Auth/Language/pt-br/MyAccount.php @@ -0,0 +1,18 @@ + 'Informações da minha conta', + 'changePassword' => 'Alterar minha senha', + 'messages' => [ + 'wrongPasswordError' => "Você digitou a senha errada, tente novamente.", + 'passwordChangeSuccess' => 'Senha foi alterada com sucesso!', + ], +]; diff --git a/modules/Auth/Language/pt-br/User.php b/modules/Auth/Language/pt-br/User.php new file mode 100644 index 00000000..945f8609 --- /dev/null +++ b/modules/Auth/Language/pt-br/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Banir', + 'unban' => 'Desbanir', + 'delete' => 'Excluir', + 'create' => 'Novo usuário', + 'view' => "Informações de {username}", + 'all_users' => 'Todos os usuários', + 'list' => [ + 'user' => 'Usuário', + 'role' => 'Role', + 'banned' => 'Banido?', + ], + 'form' => [ + 'email' => 'E-mail', + 'username' => 'Nome de usuário', + 'password' => 'Senha', + 'new_password' => 'Nova Senha', + 'role' => 'Role', + 'roles' => 'Cargos', + 'permissions' => 'Permissões', + 'submit_create' => 'Criar usuário', + 'submit_edit' => 'Salvar', + 'submit_password_change' => 'Alterar!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'Usuário criado com sucesso! {username} terá que alterar sua senha na primeira autenticação.', + 'roleEditSuccess' => + "Cargos de {username} foram atualizados com sucesso.", + 'banSuccess' => '{username} foi banido.', + 'unbanSuccess' => '{username} foi desbanido.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} é um super admin, não bloqueamos um super admin assim…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} é um super admin, você não exclui um super admin assim…', + 'deleteSuccess' => '{username} foi excluído.', + ], +]; diff --git a/modules/Auth/Language/pt/Auth.php b/modules/Auth/Language/pt/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/pt/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/pt/Contributor.php b/modules/Auth/Language/pt/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/pt/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/pt/MyAccount.php b/modules/Auth/Language/pt/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/pt/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/pt/User.php b/modules/Auth/Language/pt/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/pt/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/ro/Auth.php b/modules/Auth/Language/ro/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/ro/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/ro/Contributor.php b/modules/Auth/Language/ro/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/ro/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/ro/MyAccount.php b/modules/Auth/Language/ro/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/ro/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/ro/User.php b/modules/Auth/Language/ro/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/ro/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/ru/Auth.php b/modules/Auth/Language/ru/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/ru/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/ru/Contributor.php b/modules/Auth/Language/ru/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/ru/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/ru/MyAccount.php b/modules/Auth/Language/ru/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/ru/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/ru/User.php b/modules/Auth/Language/ru/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/ru/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/sk/Auth.php b/modules/Auth/Language/sk/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/sk/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/sk/Contributor.php b/modules/Auth/Language/sk/Contributor.php new file mode 100644 index 00000000..2f251c38 --- /dev/null +++ b/modules/Auth/Language/sk/Contributor.php @@ -0,0 +1,47 @@ + 'Prispievatelia podcastu', + 'view' => "Príspevky používateľa {username} do podcastu {podcastTitle}", + 'add' => 'Pridať prispievateľa', + 'add_contributor' => 'Pridať prispievateľa pre {0}', + 'edit_role' => 'Upraviť rolu pre {0}', + 'edit' => 'Upraviť', + 'remove' => 'Odstrániť', + 'list' => [ + 'username' => 'Meno používateľa', + 'role' => 'Rola', + ], + 'form' => [ + 'user' => 'Používateľ', + 'user_placeholder' => 'Vybrať používateľa…', + 'role' => 'Rola', + 'role_placeholder' => 'Vybrať jeho úlohu…', + 'submit_add' => 'Pridať prispievateľa', + 'submit_edit' => 'Aktualizovať rolu', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "Nemôžete odstrániť vlastníka podcastu!", + 'removeSuccess' => + 'Úspešne ste odstránili používateľa {username} z podcastu {podcastTitle}', + 'alreadyAddedError' => + "Prispievateľa, ktorého sa usiľujete pridať je už pridaný!", + ], +]; diff --git a/modules/Auth/Language/sk/MyAccount.php b/modules/Auth/Language/sk/MyAccount.php new file mode 100644 index 00000000..1e54721e --- /dev/null +++ b/modules/Auth/Language/sk/MyAccount.php @@ -0,0 +1,18 @@ + 'Informácie o mojom účte', + 'changePassword' => 'Zmeniť heslo', + 'messages' => [ + 'wrongPasswordError' => "Zadali ste nesprávne heslo, skúste znovu.", + 'passwordChangeSuccess' => 'Heslo je úspešne zmenené!', + ], +]; diff --git a/modules/Auth/Language/sk/User.php b/modules/Auth/Language/sk/User.php new file mode 100644 index 00000000..e7908f5b --- /dev/null +++ b/modules/Auth/Language/sk/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/sr-latn/Auth.php b/modules/Auth/Language/sr-latn/Auth.php new file mode 100644 index 00000000..82d4174f --- /dev/null +++ b/modules/Auth/Language/sr-latn/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Vlasnik instance', + 'description' => 'Vlasnik Castopoda.', + ], + 'superadmin' => [ + 'title' => 'Super administrator', + 'description' => 'Ima kompletnu kontrolu nad Castopod-om.', + ], + 'manager' => [ + 'title' => 'Menadžer', + 'description' => 'Upravlja sadržajem na Castopod-u.', + ], + 'podcaster' => [ + 'title' => 'Podkaster', + 'description' => 'Opšti korisnici Castopod-a.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Može pristupiti administratorskom delu Castopod-a.', + 'admin.settings' => 'Može pristupiti podešavanjima Castopod-a.', + 'users.manage' => 'Može upravljati korisnicima Castopod-a.', + 'persons.manage' => 'Može upravljati osobama.', + 'pages.manage' => 'Može upravljati stranicama.', + 'podcasts.view' => 'Može videti sve podkaste.', + 'podcasts.create' => 'Može napraviti nove podkaste.', + 'podcasts.import' => 'Može uvesti nove podkaste.', + 'fediverse.manage-blocks' => 'Može blokirati interakciju Castopoda i fedivers naloga/domena.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Vlasnik podkasta', + 'description' => 'Vlasnik podkasta.', + ], + 'admin' => [ + 'title' => 'Administrator', + 'description' => 'Ima kompletnu kontrolu nad podkastom #{id}.', + ], + 'editor' => [ + 'title' => 'Urednik', + 'description' => 'Upravlja sadržajem i objavama podkasta #{id}.', + ], + 'author' => [ + 'title' => 'Autor', + 'description' => 'Upravlja sadržajem podkasta #{id} ali ne može da ga objavi.', + ], + 'guest' => [ + 'title' => 'Gost', + 'description' => 'Saradnik na podkastu #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Može videti upravljačku tablu i analitiku podkasta #{id}.', + 'edit' => 'Može uređivati podkast #{id}.', + 'delete' => 'Može obrisati podkast #{id}.', + 'manage-import' => 'Može sinhronizovati uvezen podkast #{id}.', + 'manage-persons' => 'Može upravljati pretplatama na podkast #{id}.', + 'manage-subscriptions' => 'Može upravljati pretplatama na podkast #{id}.', + 'manage-contributors' => 'Može upravljati saradnicima na podkastu #{id}.', + 'manage-platforms' => 'Može ubaciti/izbaciti veze ka platformama podkasta #{id}.', + 'manage-publications' => 'Može objaviti podkast #{id}.', + 'manage-notifications' => 'Može videti obaveštenja i označiti ih kao pročitana za podkast #{id}.', + 'interact-as' => 'Može da komunicira kao podkast #{id} i deli, odgovara na i stavlja u omiljene postove.', + 'episodes' => [ + 'view' => 'Može videti upravljačku tablu i analitiku epizoda podkasta #{id}.', + 'create' => 'Može napraviti epizode podkasta #{id}.', + 'edit' => 'Može uređivati epizode podkasta #{id}.', + 'delete' => 'Može obrisati epizode podkasta #{id}.', + 'manage-persons' => 'Može upravljati osobama na epizodama podkasta #{id}.', + 'manage-clips' => 'Može upravljati video klipovima i zvučnim isečcima podkasta #{id}.', + 'manage-publications' => 'Može da objavi/poništi objavljivanje epizoda i postova podkasta #{id}.', + 'manage-comments' => 'Može dodati/obrisati komentar na epizodi podkasta #{id}.', + ], + ], + + // missing keys + 'code' => 'Vaša šestocifrena šifra', + + 'set_password' => 'Podesi lozinku', + + // Welcome email + 'welcomeSubject' => 'Pozvani ste na {siteName}', + 'emailWelcomeMailBody' => 'Za vas je napravljen nalog na {domain}, kliknite na link za prijavu ispod da biste postavili lozinku. Veza je važeća {numberOfHours} sati nakon slanja ove e-pošte.', +]; diff --git a/modules/Auth/Language/sr-latn/Contributor.php b/modules/Auth/Language/sr-latn/Contributor.php new file mode 100644 index 00000000..39bcbdb9 --- /dev/null +++ b/modules/Auth/Language/sr-latn/Contributor.php @@ -0,0 +1,47 @@ + 'Saradnici podkasta', + 'view' => "{username} doprinos {podcastTitle}", + 'add' => 'Dodaj saradnika', + 'add_contributor' => 'Dodaj saradnike za {0}', + 'edit_role' => 'Uredi ulogu za {0}', + 'edit' => 'Izmeni', + 'remove' => 'Ukloni', + 'list' => [ + 'username' => 'Korisničko ime', + 'role' => 'Uloga', + ], + 'form' => [ + 'user' => 'Korisnik', + 'user_placeholder' => 'Izaberi korisnika…', + 'role' => 'Uloga', + 'role_placeholder' => 'Dodaj ulogu…', + 'submit_add' => 'Dodaj saradnika', + 'submit_edit' => 'Ažuriraj ulogu', + ], + 'delete_form' => [ + 'title' => 'Ukloni {contributor}', + 'disclaimer' => + 'Obrisaćete {contributor} iz saradnika. Oni neće moći više da pristupe "{podcastTitle}".', + 'understand' => 'Razumem, želim da uklonim {contributor} iz "{podcastTitle}"', + 'submit' => 'Ukloni', + ], + 'messages' => [ + 'editSuccess' => 'Uloga uspešno promenjena!', + 'editOwnerError' => "Ne možete urediti vlasnika podkasta!", + 'removeOwnerError' => "Ne možete ukloniti vlasnika podkasta!", + 'removeSuccess' => + 'Uspešno ste uklonili {username} iz {podcastTitle}', + 'alreadyAddedError' => + "Saradnik kojeg pokušavate dodati je već dodat!", + ], +]; diff --git a/modules/Auth/Language/sr-latn/MyAccount.php b/modules/Auth/Language/sr-latn/MyAccount.php new file mode 100644 index 00000000..5fa13d74 --- /dev/null +++ b/modules/Auth/Language/sr-latn/MyAccount.php @@ -0,0 +1,18 @@ + 'Infromacije o mom nalogu', + 'changePassword' => 'Promeni moju lozinku', + 'messages' => [ + 'wrongPasswordError' => "Uneli ste pogrešnu lozinku, probajte ponovo.", + 'passwordChangeSuccess' => 'Lozinka je uspešno promenjena!', + ], +]; diff --git a/modules/Auth/Language/sr-latn/User.php b/modules/Auth/Language/sr-latn/User.php new file mode 100644 index 00000000..5e128ed8 --- /dev/null +++ b/modules/Auth/Language/sr-latn/User.php @@ -0,0 +1,60 @@ + "Uredi {username} uloge", + 'ban' => 'Zabrani', + 'unban' => 'Ukini zabranu', + 'delete' => 'Obriši', + 'create' => 'Novi korisnik', + 'view' => "Informacije o korisniku {username}", + 'all_users' => 'Svi korisnici', + 'list' => [ + 'user' => 'Korisnik', + 'role' => 'Uloga', + 'banned' => 'Zabranjen?', + ], + 'form' => [ + 'email' => 'E-pošta', + 'username' => 'Korisničko ime', + 'password' => 'Lozinka', + 'new_password' => 'Nova lozinka', + 'role' => 'Uloga', + 'roles' => 'Uloge', + 'permissions' => 'Dozvole', + 'submit_create' => 'Kreiraj korisnika', + 'submit_edit' => 'Sačuvaj', + 'submit_password_change' => 'Promeni!', + ], + 'delete_form' => [ + 'title' => 'Ukloni korisnika {user}', + 'disclaimer' => + "Spremate se da trajno uklonite korisnika {user}. Korisnik neće moći više da pristupi administratorskoj zoni.", + 'understand' => 'Shvatam, želim da trajno uklonim korisnika {user}', + 'submit' => 'Obriši', + ], + 'messages' => [ + 'createSuccess' => + 'Korisnik je uspešno kreiran! Poruka dobrodošlice je poslata E-poštom korisniku {username}. Ona sadrži vezu za prijavu a od njih će biti zatraženo resetovanje lozinke nakon prve autentifikacije.', + 'roleEditSuccess' => + "Uloge korisnika {username} su uspešno ažurirane.", + 'banSuccess' => 'Korisnik {username} je zabranjen.', + 'unbanSuccess' => 'Korisniku {username} je skinuta zabrana.', + 'editOwnerError' => + 'Korisnik {username} je vlasnik instance, prosto ne možete dirati vlasnika…', + 'banSuperAdminError' => + 'Korisnik {username} je super administrator, prosto ne možete zabraniti super administratora…', + 'deleteOwnerError' => + 'Korisnik {username} je vlasnik instance, prosto ne možete obrisati vlasnika…', + 'deleteSuperAdminError' => + 'Korisnik {username} je super administrator, prosto ne možete obrisati super administratora…', + 'deleteSuccess' => 'Korisnik {username} je obrisan.', + ], +]; diff --git a/modules/Auth/Language/sv/Auth.php b/modules/Auth/Language/sv/Auth.php new file mode 100644 index 00000000..386853fe --- /dev/null +++ b/modules/Auth/Language/sv/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instans Ägare', + 'description' => 'Castopod ägaren.', + ], + 'superadmin' => [ + 'title' => 'Super administratör', + 'description' => 'Har fullständig kontroll över Castopod.', + ], + 'manager' => [ + 'title' => 'Hanterare', + 'description' => 'Hanterar Castopods innehåll.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'Generella användare av Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Kan komma åt Castopod admin-området.', + 'admin.settings' => 'Kan komma åt Castopod-inställningarna.', + 'users.manage' => 'Kan hantera Castopod-användare.', + 'persons.manage' => 'Kan hantera personer.', + 'pages.manage' => 'Kan hantera sidor.', + 'podcasts.view' => 'Kan se alla podcasts.', + 'podcasts.create' => 'Kan skapa nya podcasts.', + 'podcasts.import' => 'Kan importera podcasts.', + 'fediverse.manage-blocks' => 'Kan blockera fediverse skådespelare/domäner från att interagera med Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast ägare', + 'description' => 'Podcast ägaren.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Har fullständig kontroll över podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Redigerare', + 'description' => 'Hanterar innehåll och publikationer i podcast #{id}.', + ], + 'author' => [ + 'title' => 'Författare', + 'description' => 'Hanterar innehåll i podcast #{id} men kan inte publicera dem.', + ], + 'guest' => [ + 'title' => 'Gäst', + 'description' => 'Generell bidragsgivare till podcasten #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Kan visa instrumentpanelen och analysen av podcast #{id}.', + 'edit' => 'Kan redigera podcast #{id}.', + 'delete' => 'Kan ta bort podcast #{id}.', + 'manage-import' => 'Kan synkronisera importerad podcast #{id}.', + 'manage-persons' => 'Kan hantera prenumerationer på podcast #{id}.', + 'manage-subscriptions' => 'Kan hantera prenumerationer på podcast #{id}.', + 'manage-contributors' => 'Kan hantera bidragsgivare för podcast #{id}.', + 'manage-platforms' => 'Kan sätta/ta bort plattformslänkar för podcast #{id}.', + 'manage-publications' => 'Kan publicera podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Kan interagera som podcasten #{id} för att favorita, dela eller svara på inlägg.', + 'episodes' => [ + 'view' => 'Kan visa instrumentpaneler och analyser av podcast #{id}s avsnitt.', + 'create' => 'Kan skapa avsnitt för podcast #{id}.', + 'edit' => 'Kan redigera avsnitt av podcast #{id}.', + 'delete' => 'Kan ta bort avsnitt av podcast #{id}.', + 'manage-persons' => 'Kan hantera avsnittpersoner i podcast #{id}.', + 'manage-clips' => 'Kan hantera videoklipp eller ljudklipp från podcasten #{id}.', + 'manage-publications' => 'Kan publicera/avpublicera avsnitt och inlägg i podcast #{id}.', + 'manage-comments' => 'Kan skapa/ta bort avsnitt kommentarer från podcasten #{id}.', + ], + ], + + // missing keys + 'code' => 'Din 6-siffriga kod', + + 'set_password' => 'Välj ett lösenord', + + // Welcome email + 'welcomeSubject' => 'Du har blivit inbjuden till {siteName}', + 'emailWelcomeMailBody' => 'Ett konto skapades för dig på {domain}, klicka på inloggningslänken nedan för att ange ditt lösenord. Länken är giltig i {numberOfHours} timmar efter att detta e-postmeddelande skickats.', +]; diff --git a/modules/Auth/Language/sv/Contributor.php b/modules/Auth/Language/sv/Contributor.php new file mode 100644 index 00000000..572b91ad --- /dev/null +++ b/modules/Auth/Language/sv/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Redigera', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Användarnamn', + 'role' => 'Roll', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Roll', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Uppdatera roll', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/sv/MyAccount.php b/modules/Auth/Language/sv/MyAccount.php new file mode 100644 index 00000000..78a66902 --- /dev/null +++ b/modules/Auth/Language/sv/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Ändra mitt lösenord', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/sv/User.php b/modules/Auth/Language/sv/User.php new file mode 100644 index 00000000..d5a57d48 --- /dev/null +++ b/modules/Auth/Language/sv/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Radera', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Användarnamn', + 'password' => 'Lösenord', + 'new_password' => 'Nytt lösenord', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! {username} will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, you cannot edit its roles.', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/uk/Auth.php b/modules/Auth/Language/uk/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/uk/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/uk/Contributor.php b/modules/Auth/Language/uk/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/uk/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/uk/MyAccount.php b/modules/Auth/Language/uk/MyAccount.php new file mode 100644 index 00000000..0b511d51 --- /dev/null +++ b/modules/Auth/Language/uk/MyAccount.php @@ -0,0 +1,18 @@ + 'Інформація про аккаунт', + 'changePassword' => 'Змінити мій пароль', + 'messages' => [ + 'wrongPasswordError' => "Ви ввели неправильний пароль, спробуйте ще раз.", + 'passwordChangeSuccess' => 'Ваш пароль успішно змінено.', + ], +]; diff --git a/modules/Auth/Language/uk/User.php b/modules/Auth/Language/uk/User.php new file mode 100644 index 00000000..a9383f65 --- /dev/null +++ b/modules/Auth/Language/uk/User.php @@ -0,0 +1,60 @@ + "Змінити роль «%{name}»", + 'ban' => 'Забанити', + 'unban' => 'Розбанити', + 'delete' => 'Видалити', + 'create' => 'Новий користувач', + 'view' => "{username}інформація", + 'all_users' => 'Усі користувачі', + 'list' => [ + 'user' => 'Користувач', + 'role' => 'Роль', + 'banned' => 'Забанені?', + ], + 'form' => [ + 'email' => 'Пошта', + 'username' => 'Ім\'я користувача', + 'password' => 'Пароль', + 'new_password' => 'Новий пароль', + 'role' => 'Роль', + 'roles' => 'Ролі', + 'permissions' => 'Дозволи', + 'submit_create' => 'Створити користувача', + 'submit_edit' => 'Зберегти', + 'submit_password_change' => 'Змінити', + ], + 'delete_form' => [ + 'title' => 'Видалити користувача?', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Language/zh-hans/Auth.php b/modules/Auth/Language/zh-hans/Auth.php new file mode 100644 index 00000000..b3d371e5 --- /dev/null +++ b/modules/Auth/Language/zh-hans/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => '实例所有者', + 'description' => 'Castopod 所有者', + ], + 'superadmin' => [ + 'title' => '超级管理员', + 'description' => '拥有对 Castopod 的完全控制。', + ], + 'manager' => [ + 'title' => '管理', + 'description' => '管理 Castopod 的内容。', + ], + 'podcaster' => [ + 'title' => '播客', + 'description' => 'Castopod 的普通用户。', + ], + ], + 'instance_permissions' => [ + 'admin.access' => '可以访问 Castopod 管理区域。', + 'admin.settings' => '可以访问 Castopod 设置。', + 'users.manage' => '可以管理 Castopod 用户。', + 'persons.manage' => '可以管理人员。', + 'pages.manage' => '可以管理页面。', + 'podcasts.view' => '可以查看所有播客。', + 'podcasts.create' => '可以创建新播客。', + 'podcasts.import' => '可以导入播客。', + 'fediverse.manage-blocks' => '可以阻止联邦宇宙参与者/域与 Castopod 交互。', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => '播客封面', + 'description' => '播客所有者。', + ], + 'admin' => [ + 'title' => '管理员', + 'description' => '完全控制播客 #{id}。', + ], + 'editor' => [ + 'title' => '编辑', + 'description' => '管理播客 #{id} 的内容和出版物。', + ], + 'author' => [ + 'title' => '作者', + 'description' => '管理播客 #{id} 的内容,但不能发布。', + ], + 'guest' => [ + 'title' => '访客', + 'description' => '播客 #{id} 的普通贡献者。', + ], + ], + 'podcast_permissions' => [ + 'view' => '可以查看播客 #{id} 的仪表板和分析。', + 'edit' => '可以编辑播客 #{id}。', + 'delete' => '可以删除播客 #{id}。', + 'manage-import' => '可以同步导入的播客 #{id}。', + 'manage-persons' => '可以管理播客 #{id} 的订阅。', + 'manage-subscriptions' => '可以管理播客 #{id} 的订阅。', + 'manage-contributors' => '可以管理播客 #{id} 的贡献者。', + 'manage-platforms' => '可以设置/删除播客 #{id} 的平台链接。', + 'manage-publications' => '可以发布播客 #{id}。', + 'manage-notifications' => '可以查看播客 #{id} 的通知并将其标记为已读。', + 'interact-as' => '可以在播客 #{id} 进行互动,以收藏、分享或回复帖子。', + 'episodes' => [ + 'view' => '可以查看播客 #{id} 的仪表板和分析。', + 'create' => '可以为播客 #{id} 创建剧集。', + 'edit' => '可以编辑播客 #{id} 的剧集。', + 'delete' => '可以删除播客 #{id} 的剧集。', + 'manage-persons' => '可以管理播客 #{id} 的剧集人。', + 'manage-clips' => '可以管理播客 #{id} 的视频剪辑或声音片段。', + 'manage-publications' => '可以发布/取消发布播客 #{id} 的剧集和帖子。', + 'manage-comments' => '可以创建/删除播客 #{id} 的剧集评论。', + ], + ], + + // missing keys + 'code' => '你的6位验证码', + + 'set_password' => '设置你的密码', + + // Welcome email + 'welcomeSubject' => '你已受邀加入 {siteName}', + 'emailWelcomeMailBody' => '在 {domain} 上为你创建了一个帐户,单击下面的登录链接设置您的密码。 该链接在发送此电子邮件后的 {numberOfHours} 小时内有效。', +]; diff --git a/modules/Auth/Language/zh-hans/Contributor.php b/modules/Auth/Language/zh-hans/Contributor.php new file mode 100644 index 00000000..0d28c5ad --- /dev/null +++ b/modules/Auth/Language/zh-hans/Contributor.php @@ -0,0 +1,47 @@ + '播客贡献者', + 'view' => "{username} 对 {podcastTitle} 的贡献", + 'add' => '添加贡献者', + 'add_contributor' => '为 {0} 添加贡献者', + 'edit_role' => '更新 {0} 的角色', + 'edit' => '编辑', + 'remove' => '移除', + 'list' => [ + 'username' => '用户名', + 'role' => '角色', + ], + 'form' => [ + 'user' => '用户', + 'user_placeholder' => '选择一个用户...', + 'role' => '角色', + 'role_placeholder' => '选择角色…', + 'submit_add' => '添加贡献者', + 'submit_edit' => '更新角色', + ], + 'delete_form' => [ + 'title' => '移除 {contributor}', + 'disclaimer' => + '你将要从贡献者中删除 {contributor},他们将无法再访问“{podcastTitle}”。', + 'understand' => '我明白,我想从“{podcastTitle}”中删除 {contributor}', + 'submit' => '移除', + ], + 'messages' => [ + 'editSuccess' => '已成功更改角色!', + 'editOwnerError' => "你无法编辑播客所有者!", + 'removeOwnerError' => "你无法删除播客所有者!", + 'removeSuccess' => + '你从 {username} 移除 {podcastTitle}', + 'alreadyAddedError' => + "你尝试添加的贡献者已添加!", + ], +]; diff --git a/modules/Auth/Language/zh-hans/MyAccount.php b/modules/Auth/Language/zh-hans/MyAccount.php new file mode 100644 index 00000000..3822e48f --- /dev/null +++ b/modules/Auth/Language/zh-hans/MyAccount.php @@ -0,0 +1,18 @@ + '账户信息', + 'changePassword' => '修改密码', + 'messages' => [ + 'wrongPasswordError' => "密码错误,请重试。", + 'passwordChangeSuccess' => '密码已更改!', + ], +]; diff --git a/modules/Auth/Language/zh-hans/User.php b/modules/Auth/Language/zh-hans/User.php new file mode 100644 index 00000000..5440c60a --- /dev/null +++ b/modules/Auth/Language/zh-hans/User.php @@ -0,0 +1,60 @@ + "编辑 {username} 的角色", + 'ban' => '封禁', + 'unban' => '取消封禁', + 'delete' => '删除', + 'create' => '新用户', + 'view' => "{username} 的信息", + 'all_users' => '所有用户', + 'list' => [ + 'user' => '用户', + 'role' => '角色', + 'banned' => '已封禁?', + ], + 'form' => [ + 'email' => '邮箱', + 'username' => '用户名', + 'password' => '密码', + 'new_password' => '新密码', + 'role' => '角色', + 'roles' => '角色', + 'permissions' => '权限', + 'submit_create' => '创建用户', + 'submit_edit' => '保存', + 'submit_password_change' => '修改!', + ], + 'delete_form' => [ + 'title' => '删除 {user} ?', + 'disclaimer' => + "你将永久删除 {user},他们将无法再访问管理区域。", + 'understand' => '我明白,我想永久删除 {user}', + 'submit' => '删除', + ], + 'messages' => [ + 'createSuccess' => + '用户创建成功!{username} 将在首次验证时提醒重置密码。', + 'roleEditSuccess' => + "{username} 的角色已更新。", + 'banSuccess' => '{username} 已被封禁。', + 'unbanSuccess' => '{username} 已解除封禁。', + 'editOwnerError' => + '{username} 是实例的所有者,你不能编辑他的角色。', + 'banSuperAdminError' => + '{username} 是超级管理员,不能禁止超级管理员…', + 'deleteOwnerError' => + '{username} 是实例的所有者,不能简单地删除所有者…', + 'deleteSuperAdminError' => + '{username} 是超级管理员,不能封禁超级管理员…', + 'deleteSuccess' => '{username} 已被删除。', + ], +]; diff --git a/modules/Auth/Language/zh-hant/Auth.php b/modules/Auth/Language/zh-hant/Auth.php new file mode 100644 index 00000000..b366563a --- /dev/null +++ b/modules/Auth/Language/zh-hant/Auth.php @@ -0,0 +1,95 @@ + [ + 'owner' => [ + 'title' => 'Instance Owner', + 'description' => 'The Castopod owner.', + ], + 'superadmin' => [ + 'title' => 'Super admin', + 'description' => 'Has complete control over Castopod.', + ], + 'manager' => [ + 'title' => 'Manager', + 'description' => 'Manages Castopod\'s content.', + ], + 'podcaster' => [ + 'title' => 'Podcaster', + 'description' => 'General users of Castopod.', + ], + ], + 'instance_permissions' => [ + 'admin.access' => 'Can access the Castopod admin area.', + 'admin.settings' => 'Can access the Castopod settings.', + 'users.manage' => 'Can manage Castopod users.', + 'persons.manage' => 'Can manage persons.', + 'pages.manage' => 'Can manage pages.', + 'podcasts.view' => 'Can view all podcasts.', + 'podcasts.create' => 'Can create new podcasts.', + 'podcasts.import' => 'Can import podcasts.', + 'fediverse.manage-blocks' => 'Can block fediverse actors/domains from interacting with Castopod.', + ], + 'podcast_groups' => [ + 'owner' => [ + 'title' => 'Podcast Owner', + 'description' => 'The podcast owner.', + ], + 'admin' => [ + 'title' => 'Admin', + 'description' => 'Has complete control of podcast #{id}.', + ], + 'editor' => [ + 'title' => 'Editor', + 'description' => 'Manages content and publications of podcast #{id}.', + ], + 'author' => [ + 'title' => 'Author', + 'description' => 'Manages content of podcast #{id} but cannot publish them.', + ], + 'guest' => [ + 'title' => 'Guest', + 'description' => 'General contributor of the podcast #{id}.', + ], + ], + 'podcast_permissions' => [ + 'view' => 'Can view dashboard and analytics of podcast #{id}.', + 'edit' => 'Can edit podcast #{id}.', + 'delete' => 'Can delete podcast #{id}.', + 'manage-import' => 'Can synchronize imported podcast #{id}.', + 'manage-persons' => 'Can manage subscriptions of podcast #{id}.', + 'manage-subscriptions' => 'Can manage subscriptions of podcast #{id}.', + 'manage-contributors' => 'Can manage contributors of podcast #{id}.', + 'manage-platforms' => 'Can set/remove platform links of podcast #{id}.', + 'manage-publications' => 'Can publish podcast #{id}.', + 'manage-notifications' => 'Can view and mark notifications as read for podcast #{id}.', + 'interact-as' => 'Can interact as the podcast #{id} to favourite, share or reply to posts.', + 'episodes' => [ + 'view' => 'Can view dashboards and analytics of podcast #{id}\'s episodes.', + 'create' => 'Can create episodes for podcast #{id}.', + 'edit' => 'Can edit episodes of podcast #{id}.', + 'delete' => 'Can delete episodes of podcast #{id}.', + 'manage-persons' => 'Can manage episode persons of podcast #{id}.', + 'manage-clips' => 'Can manage video clips or soundbites of podcast #{id}.', + 'manage-publications' => 'Can publish/unpublish episodes and posts of podcast #{id}.', + 'manage-comments' => 'Can create/remove episode comments of podcast #{id}.', + ], + ], + + // missing keys + 'code' => 'Your 6-digit code', + + 'set_password' => 'Set your password', + + // Welcome email + 'welcomeSubject' => 'You\'ve been invited to {siteName}', + 'emailWelcomeMailBody' => 'An account was created for you on {domain}, click on the login link below to set your password. The link is valid for {numberOfHours} hours after this email was sent.', +]; diff --git a/modules/Auth/Language/zh-hant/Contributor.php b/modules/Auth/Language/zh-hant/Contributor.php new file mode 100644 index 00000000..c70badc0 --- /dev/null +++ b/modules/Auth/Language/zh-hant/Contributor.php @@ -0,0 +1,47 @@ + 'Podcast contributors', + 'view' => "{username}'s contribution to {podcastTitle}", + 'add' => 'Add contributor', + 'add_contributor' => 'Add a contributor for {0}', + 'edit_role' => 'Update role for {0}', + 'edit' => 'Edit', + 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], + 'form' => [ + 'user' => 'User', + 'user_placeholder' => 'Select a user…', + 'role' => 'Role', + 'role_placeholder' => 'Select its role…', + 'submit_add' => 'Add contributor', + 'submit_edit' => 'Update role', + ], + 'delete_form' => [ + 'title' => 'Remove {contributor}', + 'disclaimer' => + 'You are about to remove {contributor} from contributors. They will not be able to access "{podcastTitle}" anymore.', + 'understand' => 'I understand, I want to remove {contributor} from "{podcastTitle}"', + 'submit' => 'Remove', + ], + 'messages' => [ + 'editSuccess' => 'Role successfully changed!', + 'editOwnerError' => "You can't edit the podcast owner!", + 'removeOwnerError' => "You can't remove the podcast owner!", + 'removeSuccess' => + 'You have successfully removed {username} from {podcastTitle}', + 'alreadyAddedError' => + "The contributor you're trying to add has already been added!", + ], +]; diff --git a/modules/Auth/Language/zh-hant/MyAccount.php b/modules/Auth/Language/zh-hant/MyAccount.php new file mode 100644 index 00000000..6ebbb30e --- /dev/null +++ b/modules/Auth/Language/zh-hant/MyAccount.php @@ -0,0 +1,18 @@ + 'My account info', + 'changePassword' => 'Change my password', + 'messages' => [ + 'wrongPasswordError' => "You've entered the wrong password, try again.", + 'passwordChangeSuccess' => 'Password has been successfully changed!', + ], +]; diff --git a/modules/Auth/Language/zh-hant/User.php b/modules/Auth/Language/zh-hant/User.php new file mode 100644 index 00000000..32ec560c --- /dev/null +++ b/modules/Auth/Language/zh-hant/User.php @@ -0,0 +1,60 @@ + "Edit {username}'s role", + 'ban' => 'Ban', + 'unban' => 'Unban', + 'delete' => 'Delete', + 'create' => 'New user', + 'view' => "{username}'s info", + 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'role' => 'Role', + 'banned' => 'Banned?', + ], + 'form' => [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'new_password' => 'New Password', + 'role' => 'Role', + 'roles' => 'Roles', + 'permissions' => 'Permissions', + 'submit_create' => 'Create user', + 'submit_edit' => 'Save', + 'submit_password_change' => 'Change!', + ], + 'delete_form' => [ + 'title' => 'Delete {user}', + 'disclaimer' => + "You are about to delete {user} permanently. They will not be able to access the admin area anymore.", + 'understand' => 'I understand, I want to delete {user} permanently', + 'submit' => 'Delete', + ], + 'messages' => [ + 'createSuccess' => + 'User created successfully! A welcome email was sent to {username} with a login link, they will be prompted with a password reset upon first authentication.', + 'roleEditSuccess' => + "{username}'s roles have been successfully updated.", + 'banSuccess' => '{username} has been banned.', + 'unbanSuccess' => '{username} has been unbanned.', + 'editOwnerError' => + '{username} is the instance owner, one does not simply touch the owner…', + 'banSuperAdminError' => + '{username} is a superadmin, one does not simply ban a superadmin…', + 'deleteOwnerError' => + '{username} is the instance owner, one does not simply delete the owner…', + 'deleteSuperAdminError' => + '{username} is a superadmin, one does not simply delete a superadmin…', + 'deleteSuccess' => '{username} has been deleted.', + ], +]; diff --git a/modules/Auth/Models/UserModel.php b/modules/Auth/Models/UserModel.php new file mode 100644 index 00000000..16ac112a --- /dev/null +++ b/modules/Auth/Models/UserModel.php @@ -0,0 +1,50 @@ + + */ + protected $allowedFields = [ + 'username', + 'status', + 'status_message', + 'active', + 'is_owner', + 'last_active', + 'deleted_at', + ]; + + /** + * @return User[] + */ + public function getPodcastContributors(int $podcastId): array + { + return $this->select('users.*') + ->join('auth_groups_users', 'users.id = auth_groups_users.user_id') + ->like('auth_groups_users.group', "podcast#{$podcastId}-") + ->findAll(); + } + + public function getPodcastContributor(int $contributorId, int $podcastId): ?User + { + return $this->select('users.*') + ->join('auth_groups_users', 'users.id = auth_groups_users.user_id') + ->where('users.id', $contributorId) + ->like('auth_groups_users.group', "podcast#{$podcastId}-") + ->first(); + } +} diff --git a/app/Libraries/ActivityPub/Activities/AcceptActivity.php b/modules/Fediverse/Activities/AcceptActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/AcceptActivity.php rename to modules/Fediverse/Activities/AcceptActivity.php index 9dd1e049..b13063f3 100644 --- a/app/Libraries/ActivityPub/Activities/AcceptActivity.php +++ b/modules/Fediverse/Activities/AcceptActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class AcceptActivity extends Activity { diff --git a/modules/Fediverse/Activities/AnnounceActivity.php b/modules/Fediverse/Activities/AnnounceActivity.php new file mode 100644 index 00000000..cb262de4 --- /dev/null +++ b/modules/Fediverse/Activities/AnnounceActivity.php @@ -0,0 +1,32 @@ +actor = $reblogPost->actor->uri; + $this->object = $reblogPost->reblog_of_post->uri; + + $this->published = $reblogPost->published_at->format(DATE_W3C); + + $this->cc = [$reblogPost->actor->uri, $reblogPost->actor->followers_url]; + } +} diff --git a/app/Libraries/ActivityPub/Activities/CreateActivity.php b/modules/Fediverse/Activities/CreateActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/CreateActivity.php rename to modules/Fediverse/Activities/CreateActivity.php index 42bc4d54..1af38fa0 100644 --- a/app/Libraries/ActivityPub/Activities/CreateActivity.php +++ b/modules/Fediverse/Activities/CreateActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class CreateActivity extends Activity { diff --git a/app/Libraries/ActivityPub/Activities/DeleteActivity.php b/modules/Fediverse/Activities/DeleteActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/DeleteActivity.php rename to modules/Fediverse/Activities/DeleteActivity.php index 015b5310..e7454bd6 100644 --- a/app/Libraries/ActivityPub/Activities/DeleteActivity.php +++ b/modules/Fediverse/Activities/DeleteActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class DeleteActivity extends Activity { diff --git a/app/Libraries/ActivityPub/Activities/FollowActivity.php b/modules/Fediverse/Activities/FollowActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/FollowActivity.php rename to modules/Fediverse/Activities/FollowActivity.php index ee8f7b4b..5bdee934 100644 --- a/app/Libraries/ActivityPub/Activities/FollowActivity.php +++ b/modules/Fediverse/Activities/FollowActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class FollowActivity extends Activity { diff --git a/app/Libraries/ActivityPub/Activities/LikeActivity.php b/modules/Fediverse/Activities/LikeActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/LikeActivity.php rename to modules/Fediverse/Activities/LikeActivity.php index ce563429..13e98b4f 100644 --- a/app/Libraries/ActivityPub/Activities/LikeActivity.php +++ b/modules/Fediverse/Activities/LikeActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class LikeActivity extends Activity { diff --git a/app/Libraries/ActivityPub/Activities/UndoActivity.php b/modules/Fediverse/Activities/UndoActivity.php similarity index 80% rename from app/Libraries/ActivityPub/Activities/UndoActivity.php rename to modules/Fediverse/Activities/UndoActivity.php index 222b164b..482aa9ce 100644 --- a/app/Libraries/ActivityPub/Activities/UndoActivity.php +++ b/modules/Fediverse/Activities/UndoActivity.php @@ -6,14 +6,14 @@ declare(strict_types=1); * Activity objects are specializations of the base Object type that provide information about actions that have either * already occurred, are in the process of occurring, or may occur in the future. * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Activities; +namespace Modules\Fediverse\Activities; -use ActivityPub\Core\Activity; +use Modules\Fediverse\Core\Activity; class UndoActivity extends Activity { diff --git a/modules/Fediverse/ActivityRequest.php b/modules/Fediverse/ActivityRequest.php new file mode 100644 index 00000000..f5b56a29 --- /dev/null +++ b/modules/Fediverse/ActivityRequest.php @@ -0,0 +1,116 @@ + + */ + protected array $options = []; + + public function __construct(string $uri, ?string $activityPayload = null) + { + $this->request = service('curlrequest'); + + if ($activityPayload !== null) { + $this->request->setBody($activityPayload); + } + + $this->options = [ + 'headers' => [ + 'Content-Type' => 'application/activity+json', + 'Accept' => 'application/activity+json', + 'User-Agent' => 'Castopod/' . CP_VERSION . '; +' . base_url('', 'https'), + // TODO: outgoing and incoming requests + ], + ]; + + $this->uri = new URI($uri); + } + + public function post(): void + { + // outgoing message to Fediverse instance + $this->request->post((string) $this->uri, $this->options); + } + + public function get(): ResponseInterface + { + return $this->request->get((string) $this->uri, $this->options); + } + + public function getDomain(): string + { + return $this->uri->getHost() . + ($this->uri->getPort() ? ':' . $this->uri->getPort() : ''); + } + + public function sign(string $keyId, string $privateKey): void + { + $rsa = new RSA(); + $rsa->loadKey($privateKey); + $rsa->setHash('sha256'); + $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); + + $path = + $this->uri->getPath() . + ($this->uri->getQuery() !== '' ? "?{$this->uri->getQuery()}" : ''); + $host = $this->uri->getHost(); + $date = Time::now('GMT')->format('D, d M Y H:i:s T'); + $digest = 'SHA-256=' . base64_encode($this->getBodyDigest()); + $contentType = $this->options['headers']['Content-Type']; + $contentLength = (string) strlen((string) $this->request->getBody()); + $userAgent = 'Castopod/' . CP_VERSION . '; +' . base_url('', 'https'); + + $plainText = "(request-target): post {$path}\nhost: {$host}\ndate: {$date}\ndigest: {$digest}\ncontent-type: {$contentType}\ncontent-length: {$contentLength}\nuser-agent: {$userAgent}"; + + $signature = $rsa->sign($plainText); + + $signatureHeader = + 'keyId="' . + $keyId . + '",algorithm="rsa-sha256",headers="(request-target) host date digest content-type content-length user-agent",signature="' . + base64_encode($signature) . + '"'; + + $this->options = [ + 'headers' => [ + 'Content-Type' => $contentType, + 'Content-Length' => $contentLength, + 'Authorization' => "Signature {$signatureHeader}", + 'Signature' => $signatureHeader, + 'Host' => $host, + 'Date' => $date, + 'User-Agent' => $userAgent, + 'Digest' => $digest, + ], + ]; + } + + protected function getBodyDigest(): string + { + return hash('sha256', (string) $this->request->getBody(), true); + } +} diff --git a/modules/Fediverse/Commands/Broadcast.php b/modules/Fediverse/Commands/Broadcast.php new file mode 100644 index 00000000..3e096946 --- /dev/null +++ b/modules/Fediverse/Commands/Broadcast.php @@ -0,0 +1,71 @@ +getScheduledActivities(10); + + foreach ($scheduledActivities as $scheduledActivity) { + // set activity post to processing + model('ActivityModel', false) + ->update($scheduledActivity->id, [ + 'status' => 'processing', + ]); + } + + // Send activity to all followers + foreach ($scheduledActivities as $scheduledActivity) { + try { + if ($scheduledActivity->target_actor_id !== null) { + if ($scheduledActivity->actor_id !== $scheduledActivity->target_actor_id) { + // send activity to targeted actor + send_activity_to_actor( + $scheduledActivity->actor, + $scheduledActivity->targetActor, + json_encode($scheduledActivity->payload, JSON_THROW_ON_ERROR), + ); + } + } else { + // send activity to all actor followers + send_activity_to_followers( + $scheduledActivity->actor, + json_encode($scheduledActivity->payload, JSON_THROW_ON_ERROR), + ); + } + + // set activity post to delivered + model('ActivityModel', false) + ->update($scheduledActivity->id, [ + 'status' => 'delivered', + ]); + + } catch (Exception) { + // set activity post to delivered + model('ActivityModel', false) + ->update($scheduledActivity->id, [ + 'status' => 'failed', + ]); + } + } + } +} diff --git a/modules/Fediverse/Config/Fediverse.php b/modules/Fediverse/Config/Fediverse.php new file mode 100644 index 00000000..a35e88dd --- /dev/null +++ b/modules/Fediverse/Config/Fediverse.php @@ -0,0 +1,48 @@ + + */ + public static function Filters(): array + { + return [ + 'aliases' => [ + 'fediverse' => FediverseFilter::class, + ], + ]; + } +} diff --git a/modules/Fediverse/Config/Routes.php b/modules/Fediverse/Config/Routes.php new file mode 100644 index 00000000..1fb7fe0c --- /dev/null +++ b/modules/Fediverse/Config/Routes.php @@ -0,0 +1,109 @@ +addPlaceholder('actorUsername', '[a-zA-Z0-9\_]{1,32}'); +$routes->addPlaceholder( + 'uuid', + '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}', +); +$routes->addPlaceholder('postAction', '\bfavourite|\breblog|\breply'); + +/** + * Fediverse routes file + */ + +$routes->group('', [ + 'namespace' => 'Modules\Fediverse\Controllers', +], static function ($routes): void { + // webfinger + $routes->get('.well-known/webfinger', 'WebFingerController', [ + 'as' => 'webfinger', + ]); + // nodeInfo2 + $routes->get('.well-known/x-nodeinfo2', 'NodeInfo2Controller', [ + 'as' => 'nodeInfo2', + ]); + // Actor + $routes->group('@(:actorUsername)', static function ($routes): void { + // Actor + $routes->get('/', 'ActorController::index/$1', [ + 'as' => 'actor', + ]); + $routes->post('inbox', 'ActorController::inbox/$1', [ + 'as' => 'inbox', + 'filter' => 'fediverse:verify-activitystream,verify-blocks,verify-signature', + ]); + $routes->get('outbox', 'ActorController::outbox/$1', [ + 'as' => 'outbox', + 'filter' => 'fediverse:verify-activitystream', + ]); + $routes->get('followers', 'ActorController::followers/$1', [ + 'as' => 'followers', + 'filter' => 'fediverse::activity-stream', + ]); + $routes->post('follow', 'ActorController::followAction/$1', [ + 'as' => 'attempt-follow', + ]); + $routes->get('activities/(:uuid)', 'ActorController::activity/$1/$2', [ + 'as' => 'activity', + ]); + }); + // Post + $routes->post('posts/create', 'PostController::createAction/$1', [ + 'as' => 'post-attempt-create', + ]); + $routes->get('posts/(:uuid)', 'PostController::index/$1', [ + 'as' => 'post', + ]); + $routes->get('posts/(:uuid)/replies', 'PostController::index/$1', [ + 'as' => 'post-replies', + ]); + $routes->post( + 'posts/(:uuid)/remote/(:postAction)', + 'PostController::remoteActionAction/$1/$2/$3', + [ + 'as' => 'post-attempt-remote-action', + ], + ); + // Blocking actors and domains + $routes->post( + 'fediverse-block-actor', + 'BlockController::blockActorAction', + [ + 'as' => 'fediverse-attempt-block-actor', + ], + ); + $routes->post( + 'fediverse-block-domain', + 'BlockController::blockDomainAction', + [ + 'as' => 'fediverse-attempt-block-domain', + ], + ); + $routes->post( + 'fediverse-unblock-actor', + 'BlockController::unblockActorAction', + [ + 'as' => 'fediverse-attempt-unblock-actor', + ], + ); + $routes->post( + 'fediverse-unblock-domain', + 'BlockController::unblockDomainAction', + [ + 'as' => 'fediverse-attempt-unblock-domain', + ], + ); + $routes->cli('scheduled-activities', 'SchedulerController::activity'); +}); diff --git a/modules/Fediverse/Controllers/ActivityPubController.php b/modules/Fediverse/Controllers/ActivityPubController.php new file mode 100644 index 00000000..bceee417 --- /dev/null +++ b/modules/Fediverse/Controllers/ActivityPubController.php @@ -0,0 +1,27 @@ +response->setHeader('Access-Control-Allow-Origin', '*') // for allowing any domain, insecure + ->setHeader('Access-Control-Allow-Headers', '*') // for allowing any headers, insecure + ->setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS') // allows GET and OPTIONS methods only + ->setHeader('Access-Control-Max-Age', '86400') + ->setHeader('Cache-Control', 'public, max-age=86400') + ->setStatusCode(200); + } +} diff --git a/modules/Fediverse/Controllers/ActorController.php b/modules/Fediverse/Controllers/ActorController.php new file mode 100644 index 00000000..a567436b --- /dev/null +++ b/modules/Fediverse/Controllers/ActorController.php @@ -0,0 +1,394 @@ + + */ + protected $helpers = ['fediverse']; + + protected Actor $actor; + + protected Fediverse $config; + + public function __construct() + { + $this->config = config('Fediverse'); + } + + public function _remap(string $method, string ...$params): mixed + { + if (count($params) < 1) { + throw PageNotFoundException::forPageNotFound(); + } + + if ( + ! ($actor = model('ActorModel', false)->getActorByUsername($params[0])) instanceof Actor + ) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->actor = $actor; + unset($params[0]); + + return $this->{$method}(...$params); + } + + public function index(): ResponseInterface + { + $actorObjectClass = $this->config->actorObject; + $actorObject = new $actorObjectClass($this->actor); + + return $this->response + ->setContentType('application/activity+json') + ->setBody($actorObject->toJSON()); + } + + /** + * Handles incoming requests from fediverse servers + */ + public function inbox(): ResponseInterface + { + // get json body and parse it + $payload = $this->request->getJSON(); + + // retrieve payload actor from database or create it if it doesn't exist + $payloadActor = get_or_create_actor_from_uri($payload->actor); + + // store activity to database + $activityId = model('ActivityModel', false) + ->newActivity( + $payload->type, + $payloadActor->id, + $this->actor->id, + null, + json_encode($payload, JSON_THROW_ON_ERROR), + ); + + // switch/case on activity type + switch ($payload->type) { + case 'Create': + if ($payload->object->type === 'Note') { + if (! $payload->object->inReplyTo) { + return $this->response->setStatusCode(501) + ->setJSON([]); + } + + $replyToPost = model('PostModel', false) + ->getPostByUri($payload->object->inReplyTo); + + $reply = null; + if ($replyToPost instanceof Post) { + // TODO: strip content from html to retrieve message + // remove all html tags and reconstruct message with mentions? + $message = get_message_from_object($payload->object); + + $reply = new Post([ + 'uri' => $payload->object->id, + 'actor_id' => $payloadActor->id, + 'in_reply_to_id' => $replyToPost->id, + 'message' => $message, + 'is_private' => ! is_note_public($payload->object), + 'published_at' => Time::parse($payload->object->published), + ]); + } + + if ($reply instanceof Post) { + $postId = model('PostModel', false) + ->addReply($reply, true, false); + + model('ActivityModel', false) + ->update($activityId, [ + 'post_id' => $postId, + ]); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + } + + // return not handled undo error (501 = not implemented) + return $this->response->setStatusCode(501) + ->setJSON([]); + case 'Delete': + $postToDelete = model('PostModel', false) + ->getPostByUri($payload->object); + + if ($postToDelete instanceof Post) { + model('PostModel', false) + ->removePost($postToDelete, false); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + case 'Follow': + // add to followers table + model('FollowModel', false) + ->addFollower($payloadActor, $this->actor, false); + + // Automatically accept follow by returning accept activity + accept_follow($this->actor, $payloadActor, $payload->id); + + // TODO: return 202 (Accepted) followed! + return $this->response->setStatusCode(202) + ->setJSON([]); + + case 'Like': + // get favourited post + $post = model('PostModel', false) + ->getPostByUri($payload->object); + + if ($post instanceof Post) { + // Like side-effect + model('FavouriteModel', false) + ->addFavourite($payloadActor, $post, false); + + model('ActivityModel', false) + ->update($activityId, [ + 'post_id' => $post->id, + ]); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + case 'Announce': + $post = model('PostModel', false) + ->getPostByUri($payload->object); + + if ($post instanceof Post) { + model('ActivityModel', false) + ->update($activityId, [ + 'post_id' => $post->id, + ]); + + model('PostModel', false) + ->reblog($payloadActor, $post, false); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + case 'Undo': + // switch/case on the type of activity to undo + switch ($payload->object->type) { + case 'Follow': + // revert side-effect by removing follow from database + model('FollowModel', false) + ->removeFollower($payloadActor, $this->actor, false); + + // TODO: undo has been accepted! (202 - Accepted) + return $this->response->setStatusCode(202) + ->setJSON([]); + case 'Like': + $post = model('PostModel', false) + ->getPostByUri($payload->object->object); + + if ($post instanceof Post) { + // revert side-effect by removing favourite from database + model('FavouriteModel', false) + ->removeFavourite($payloadActor, $post, false); + + model('ActivityModel', false) + ->update($activityId, [ + 'post_id' => $post->id, + ]); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + case 'Announce': + $post = model('PostModel', false) + ->getPostByUri($payload->object->object); + + $reblogPost = null; + if ($post instanceof Post) { + $reblogPost = model('PostModel', false) + ->where([ + 'actor_id' => $payloadActor->id, + 'reblog_of_id' => service('uuid') + ->fromString($post->id) + ->getBytes(), + ]) + ->first(); + } + + if ($reblogPost instanceof \App\Entities\Post) { + model('PostModel', false) + ->undoReblog($reblogPost, false); + + model('ActivityModel', false) + ->update($activityId, [ + 'post_id' => $post->id, + ]); + } + + return $this->response->setStatusCode(200) + ->setJSON([]); + default: + // return not handled undo error (501 = not implemented) + return $this->response->setStatusCode(501) + ->setJSON([]); + } + // no break + default: + // return not handled activity error (501 = not implemented) + return $this->response->setStatusCode(501) + ->setJSON([]); + } + } + + public function outbox(): ResponseInterface + { + // get published activities by publication date + /** @var ActivityModel $actorActivity */ + $actorActivity = model('ActivityModel', false) + ->where('actor_id', $this->actor->id) + ->where('`created_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('created_at', 'DESC'); + + $pageNumber = (int) $this->request->getGet('page'); + + if ($pageNumber < 1) { + $actorActivity->paginate(12); + $pager = $actorActivity->pager; + $collection = new OrderedCollectionObject(null, $pager); + } else { + /** @var Activity[] $paginatedActivity */ + $paginatedActivity = $actorActivity->paginate(12, 'default', $pageNumber); + $pager = $actorActivity->pager; + $orderedItems = []; + foreach ($paginatedActivity as $activity) { + $orderedItems[] = $activity->payload; + } + + $collection = new OrderedCollectionPage($pager, $orderedItems); + } + + return $this->response + ->setContentType('application/activity+json') + ->setBody($collection->toJSON()); + } + + public function followers(): ResponseInterface + { + // get followers for a specific actor + /** @var ActorModel $followers */ + $followers = model('ActorModel', false) + ->join('fediverse_follows', 'fediverse_follows.actor_id = id', 'inner') + ->where('fediverse_follows.target_actor_id', $this->actor->id) + ->orderBy('fediverse_follows.created_at', 'DESC'); + + $pageNumber = (int) $this->request->getGet('page'); + + if ($pageNumber < 1) { + $followers->paginate(12); + $pager = $followers->pager; + $followersCollection = new OrderedCollectionObject(null, $pager); + } else { + /** @var Actor[] $paginatedFollowers */ + $paginatedFollowers = $followers->paginate(12, 'default', $pageNumber); + $pager = $followers->pager; + + $orderedItems = []; + foreach ($paginatedFollowers as $follower) { + $orderedItems[] = $follower->uri; + } + + $followersCollection = new OrderedCollectionPage($pager, $orderedItems); + } + + return $this->response + ->setContentType('application/activity+json') + ->setBody($followersCollection->toJSON()); + } + + public function followAction(): RedirectResponse + { + $rules = [ + 'handle' => 'regex_match[/^@?(?P[\w\.\-]+)@(?P[\w\.\-]+)(?P:[\d]+)?$/]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + helper('text'); + + // get webfinger data from actor + // parse actor id to get actor and domain + // check if actor and domain exist + + $handle = $validData['handle']; + $parts = split_handle($handle); + + try { + $data = get_webfinger_data($parts['username'], $parts['domain']); + } catch (Exception) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Fediverse.follow.accountNotFound')); + } + + $ostatusKey = array_search( + 'http://ostatus.org/schema/1.0/subscribe', + array_column($data->links, 'rel'), + true, + ); + + if (! $ostatusKey) { + // TODO: error, couldn't subscribe to activitypub account + // The instance doesn't allow its users to follow others + return redirect() + ->back() + ->withInput() + ->with('error', lang('Fediverse.follow.remoteFollowNotAllowed')); + } + + return redirect()->to( + str_replace('{uri}', urlencode($this->actor->uri), (string) $data->links[$ostatusKey]->template), + ); + } + + public function activity(string $activityId): ResponseInterface + { + if ( + ! ($activity = model('ActivityModel', false)->getActivityById($activityId)) instanceof Activity + ) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->response + ->setContentType('application/activity+json') + ->setBody(json_encode($activity->payload, JSON_THROW_ON_ERROR)); + } +} diff --git a/modules/Fediverse/Controllers/BlockController.php b/modules/Fediverse/Controllers/BlockController.php new file mode 100644 index 00000000..e5304b0b --- /dev/null +++ b/modules/Fediverse/Controllers/BlockController.php @@ -0,0 +1,132 @@ + + */ + protected $helpers = ['fediverse']; + + public function blockActorAction(): RedirectResponse + { + $rules = [ + 'handle' => 'required|regex_match[/^@?([\w\.\-]+)@([\w\.\-]+)(:[\d]+)?$/]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $handle = $validData['handle']; + + if ($parts = split_handle($handle)) { + try { + $actor = get_or_create_actor($parts['username'], $parts['domain']); + } catch (Exception) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Fediverse.messages.actorNotFound')); + } + + model('ActorModel', false) + ->blockActor($actor->id); + } + + return redirect()->back() + ->with('message', lang('Fediverse.messages.blockActorSuccess', [ + 'actor' => $handle, + ])); + } + + public function unblockActorAction(): RedirectResponse + { + $rules = [ + 'actor_id' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + model('ActorModel', false) + ->unblockActor((int) $validData['actor_id']); + + return redirect()->back() + ->with('message', lang('Fediverse.messages.unblockActorSuccess')); + } + + public function blockDomainAction(): RedirectResponse + { + $rules = [ + 'domain' => 'required|regex_match[/^[\w\-\.]+[\w]+(:[\d]+)?/]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $domain = $validData['domain']; + model('BlockedDomainModel', false) + ->blockDomain($domain); + + return redirect()->back() + ->with('message', lang('Fediverse.messages.blockDomainSuccess', [ + 'domain' => $domain, + ])); + } + + public function unblockDomainAction(): RedirectResponse + { + $rules = [ + 'domain' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $domain = $validData['domain']; + model('BlockedDomainModel', false) + ->unblockDomain($domain); + + return redirect()->back() + ->with('message', lang('Fediverse.messages.unblockDomainSuccess', [ + 'domain' => $domain, + ])); + } +} diff --git a/modules/Fediverse/Controllers/NodeInfo2Controller.php b/modules/Fediverse/Controllers/NodeInfo2Controller.php new file mode 100644 index 00000000..4457c600 --- /dev/null +++ b/modules/Fediverse/Controllers/NodeInfo2Controller.php @@ -0,0 +1,52 @@ +getTotalLocalActors(); + $totalPosts = model('PostModel', false) + ->getTotalLocalPosts(); + $activeMonth = model('ActorModel', false) + ->getActiveLocalActors(1); + $activeHalfyear = model('ActorModel', false) + ->getActiveLocalActors(6); + + $nodeInfo2 = [ + 'version' => '1.0', + 'server' => [ + 'baseUrl' => base_url(), + 'name' => esc(service('settings') ->get('App.siteName')), + 'software' => 'Castopod', + 'version' => CP_VERSION, + ], + 'protocols' => ['activitypub'], + 'openRegistrations' => config('Auth') + ->allowRegistration, + 'usage' => [ + 'users' => [ + 'total' => $totalUsers, + 'activeMonth' => $activeMonth, + 'activeHalfyear' => $activeHalfyear, + ], + 'localPosts' => $totalPosts, + ], + ]; + + return $this->response->setJSON($nodeInfo2); + } +} diff --git a/modules/Fediverse/Controllers/PostController.php b/modules/Fediverse/Controllers/PostController.php new file mode 100644 index 00000000..8fdd4548 --- /dev/null +++ b/modules/Fediverse/Controllers/PostController.php @@ -0,0 +1,298 @@ + + */ + protected $helpers = ['fediverse']; + + /** + * @var Post + */ + protected $post; + + protected Fediverse $config; + + public function __construct() + { + $this->config = config('Fediverse'); + } + + public function _remap(string $method, string ...$params): mixed + { + if ($params === []) { + throw PageNotFoundException::forPageNotFound(); + } + + if (! ($post = model('PostModel', false)->getPostById($params[0])) instanceof Post) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->post = $post; + + unset($params[0]); + + return $this->{$method}(...$params); + } + + public function index(): ResponseInterface + { + $noteObjectClass = $this->config->noteObject; + $noteObject = new $noteObjectClass($this->post); + + return $this->response + ->setContentType('application/activity+json') + ->setBody($noteObject->toJSON()); + } + + public function replies(): ResponseInterface + { + /** + * get post replies + */ + $postReplies = model('PostModel', false) + ->where('in_reply_to_id', service('uuid') ->fromString($this->post->id) ->getBytes()) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'ASC'); + + $pageNumber = (int) $this->request->getGet('page'); + + if ($pageNumber < 1) { + $postReplies->paginate(12); + $pager = $postReplies->pager; + $collection = new OrderedCollectionObject(null, $pager); + } else { + $paginatedReplies = $postReplies->paginate(12, 'default', $pageNumber); + $pager = $postReplies->pager; + + $orderedItems = []; + $noteObjectClass = $this->config->noteObject; + + foreach ($paginatedReplies as $reply) { + $replyObject = new $noteObjectClass($reply); + $orderedItems[] = $replyObject->toArray(); + } + + $collection = new OrderedCollectionPage($pager, $orderedItems); + } + + return $this->response + ->setContentType('application/activity+json') + ->setBody($collection->toJSON()); + } + + public function createAction(): RedirectResponse + { + $rules = [ + 'actor_id' => 'required|is_natural_no_zero', + 'message' => 'required|max_length[500]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newPost = new Post([ + 'actor_id' => $validData['actor_id'], + 'message' => $validData['message'], + 'published_at' => Time::now(), + ]); + + $postModel = model('PostModel', false); + if (! $postModel->addPost($newPost)) { + return redirect() + ->back() + ->withInput() + // TODO: translate + ->with('error', $postModel->errors()); + } + + // Post without preview card has been successfully created + return redirect()->back(); + } + + public function favouriteAction(): RedirectResponse + { + $rules = [ + 'actor_id' => 'required|is_natural_no_zero', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $actor = model('ActorModel', false) + ->getActorById($validData['actor_id']); + + model('FavouriteModel', false) + ->toggleFavourite($actor, $this->post); + + return redirect()->back(); + } + + public function reblogAction(): RedirectResponse + { + $rules = [ + 'actor_id' => 'required|is_natural_no_zero', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $actor = model('ActorModel', false) + ->getActorById($validData['actor_id']); + + model('PostModel', false) + ->toggleReblog($actor, $this->post); + + return redirect()->back(); + } + + public function replyAction(): RedirectResponse + { + $rules = [ + 'actor_id' => 'required|is_natural_no_zero', + 'message' => 'required|max_length[500]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $newReplyPost = new Post([ + 'actor_id' => $validData['actor_id'], + 'in_reply_to_id' => $this->post->id, + 'message' => $validData['message'], + 'published_at' => Time::now(), + ]); + + if (! model('PostModel', false)->addReply($newReplyPost)) { + return redirect() + ->back() + ->withInput() + // TODO: translate + ->with('error', "Couldn't create Reply"); + } + + // Reply post without preview card has been successfully created + return redirect()->back(); + } + + public function remoteActionAction(string $action): RedirectResponse | ResponseInterface + { + $rules = [ + 'handle' => 'regex_match[/^@?(?P[\w\.\-]+)@(?P[\w\.\-]+)(?P:[\d]+)?$/]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + helper('text'); + + // get webfinger data from actor + // parse actor id to get actor and domain + // check if actor and domain exist + if ( + ! ($parts = split_handle($validData['handle'])) || + ! ($data = get_webfinger_data($parts['username'], $parts['domain'])) + ) { + return redirect() + ->back() + ->withInput() + ->with('error', lang('Fediverse.follow.accountNotFound')); + } + + $ostatusKey = array_search( + 'http://ostatus.org/schema/1.0/subscribe', + array_column($data->links, 'rel'), + true, + ); + + if (! $ostatusKey) { + // TODO: error, couldn't remote favourite/share/reply to post + // The instance doesn't allow its users remote actions on posts + return $this->response->setJSON([]); + } + + return redirect()->to( + str_replace('{uri}', urlencode($this->post->uri), (string) $data->links[$ostatusKey]->template), + ); + } + + public function blockActorAction(): RedirectResponse + { + model('ActorModel', false)->blockActor($this->post->actor->id); + + return redirect()->back(); + } + + public function blockDomainAction(): RedirectResponse + { + model('BlockedDomainModel', false)->blockDomain($this->post->actor->domain); + + return redirect()->back(); + } + + public function deleteAction(): RedirectResponse + { + model('PostModel', false)->removePost($this->post); + + return redirect()->back(); + } +} diff --git a/app/Libraries/ActivityPub/Controllers/WebFingerController.php b/modules/Fediverse/Controllers/WebFingerController.php similarity index 86% rename from app/Libraries/ActivityPub/Controllers/WebFingerController.php rename to modules/Fediverse/Controllers/WebFingerController.php index 7e6adab0..a4e2bf41 100644 --- a/app/Libraries/ActivityPub/Controllers/WebFingerController.php +++ b/modules/Fediverse/Controllers/WebFingerController.php @@ -3,18 +3,18 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Controllers; +namespace Modules\Fediverse\Controllers; -use ActivityPub\WebFinger; use CodeIgniter\Controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\ResponseInterface; use Exception; +use Modules\Fediverse\WebFinger; class WebFingerController extends Controller { diff --git a/modules/Fediverse/Core/AbstractObject.php b/modules/Fediverse/Core/AbstractObject.php new file mode 100644 index 00000000..81a21b05 --- /dev/null +++ b/modules/Fediverse/Core/AbstractObject.php @@ -0,0 +1,52 @@ +{$property} = $value; + + return $this; + } + + /** + * @return array + */ + public function toArray(): array + { + $objectVars = get_object_vars($this); + $array = []; + foreach ($objectVars as $key => $value) { + if ($key === 'context') { + $key = '@context'; + } + + $array[$key] = + is_object($value) && is_subclass_of($value, self::class) + ? $value->toArray() + : $value; + } + + // removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values + return array_filter($array, static fn ($value): bool => ! in_array($value, [null, false, ''], true)); + } + + public function toJSON(): string + { + return (string) json_encode($this->toArray(), JSON_UNESCAPED_UNICODE); + } +} diff --git a/modules/Fediverse/Core/Activity.php b/modules/Fediverse/Core/Activity.php new file mode 100644 index 00000000..eb70e07a --- /dev/null +++ b/modules/Fediverse/Core/Activity.php @@ -0,0 +1,23 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'uri' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'username' => [ + 'type' => 'VARCHAR', + 'constraint' => 32, + ], + 'domain' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'private_key' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'public_key' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'display_name' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + ], + 'summary' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'avatar_image_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + // constraint is 13 because the longest safe mimetype for images is image/svg+xml, + // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types + 'avatar_image_mimetype' => [ + 'type' => 'VARCHAR', + 'constraint' => 13, + 'null' => true, + ], + 'cover_image_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + 'cover_image_mimetype' => [ + 'type' => 'VARCHAR', + 'constraint' => 13, + 'null' => true, + ], + 'inbox_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'outbox_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + 'followers_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + 'followers_count' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 0, + ], + 'posts_count' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 0, + ], + 'is_blocked' => [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + 'updated_at' => [ + 'type' => 'DATETIME', + ], + ]); + $this->forge->addPrimaryKey('id'); + $this->forge->addUniqueKey('uri'); + $this->forge->addUniqueKey(['username', 'domain']); + $this->forge->createTable('fediverse_actors'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_actors'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php b/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php new file mode 100644 index 00000000..c6bffce5 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-020000_add_posts.php @@ -0,0 +1,95 @@ +forge->addField([ + 'id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + ], + 'uri' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'in_reply_to_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + 'null' => true, + ], + 'reblog_of_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + 'null' => true, + ], + 'message' => [ + 'type' => 'VARCHAR', + 'constraint' => 500, + 'null' => true, + ], + 'message_html' => [ + 'type' => 'VARCHAR', + 'constraint' => 600, + 'null' => true, + ], + 'favourites_count' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 0, + ], + 'reblogs_count' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 0, + ], + 'replies_count' => [ + 'type' => 'INT', + 'unsigned' => true, + 'default' => 0, + ], + 'published_at' => [ + 'type' => 'DATETIME', + 'null' => true, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addPrimaryKey('id'); + $this->forge->addUniqueKey('uri'); + // FIXME: an actor must reblog a post only once + // $this->forge->addUniqueKey(['actor_id', 'reblog_of_id']); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('in_reply_to_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('reblog_of_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_posts'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_posts'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php new file mode 100644 index 00000000..b497009b --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_activities.php @@ -0,0 +1,75 @@ +forge->addField([ + 'id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + ], + 'actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'target_actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'null' => true, + ], + 'post_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + 'null' => true, + ], + 'type' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + ], + 'payload' => [ + 'type' => 'JSON', + ], + 'status' => [ + 'type' => 'ENUM', + 'constraint' => ['queued', 'delivered'], + 'null' => true, + ], + 'scheduled_at' => [ + 'type' => 'DATETIME', + 'null' => true, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addPrimaryKey('id'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_activities'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_activities'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php new file mode 100644 index 00000000..be9b5755 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_favourites.php @@ -0,0 +1,46 @@ +forge->addField([ + 'actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'post_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + ], + ]); + + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addPrimaryKey(['actor_id', 'post_id']); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_favourites'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_favourites'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php new file mode 100644 index 00000000..945933f4 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_follows.php @@ -0,0 +1,48 @@ +forge->addField([ + 'actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'comment' => 'Actor that is following', + ], + 'target_actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'comment' => 'Actor that is followed', + ], + ]); + + $this->forge->addField('`created_at` timestamp NOT NULL DEFAULT current_timestamp()'); + $this->forge->addPrimaryKey(['actor_id', 'target_actor_id']); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_follows'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_follows'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php new file mode 100644 index 00000000..479d7102 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-100000_add_preview_cards.php @@ -0,0 +1,88 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'url' => [ + 'type' => 'VARCHAR', + 'constraint' => 512, + ], + 'title' => [ + 'type' => 'VARCHAR', + 'constraint' => 128, + ], + 'description' => [ + 'type' => 'TEXT', + ], + 'type' => [ + 'type' => 'ENUM', + 'constraint' => ['link', 'video', 'image', 'rich'], + 'default' => 'link', + ], + 'author_name' => [ + 'type' => 'VARCHAR', + 'constraint' => 64, + 'null' => true, + ], + 'author_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + 'provider_name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'provider_url' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'image' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'html' => [ + 'type' => 'TEXT', + ], + 'updated_at' => [ + 'type' => 'DATETIME', + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addPrimaryKey('id'); + $this->forge->addUniqueKey('url'); + $this->forge->createTable('fediverse_preview_cards'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_preview_cards'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php b/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php new file mode 100644 index 00000000..3d8d4d70 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-110000_add_posts_preview_cards.php @@ -0,0 +1,45 @@ +forge->addField([ + 'post_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + ], + 'preview_card_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + ]); + + $this->forge->addPrimaryKey(['post_id', 'preview_card_id']); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('preview_card_id', 'fediverse_preview_cards', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_posts_preview_cards'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_posts_preview_cards'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php b/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php new file mode 100644 index 00000000..d17079a1 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-120000_add_blocked_domains.php @@ -0,0 +1,41 @@ +forge->addField([ + 'name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + ]); + $this->forge->addPrimaryKey('name'); + $this->forge->createTable('fediverse_blocked_domains'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_blocked_domains'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php b/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php new file mode 100644 index 00000000..a1764482 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-01-130000_add_notifications.php @@ -0,0 +1,74 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'target_actor_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'post_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + 'null' => true, + ], + 'activity_id' => [ + 'type' => 'BINARY', + 'constraint' => 16, + ], + 'type' => [ + 'type' => 'ENUM', + 'constraint' => ['like', 'follow', 'share', 'reply'], + ], + 'read_at' => [ + 'type' => 'DATETIME', + 'null' => true, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + 'updated_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addPrimaryKey('id'); + $this->forge->addForeignKey('actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('target_actor_id', 'fediverse_actors', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('post_id', 'fediverse_posts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('activity_id', 'fediverse_activities', 'id', '', 'CASCADE'); + $this->forge->createTable('fediverse_notifications'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('fediverse_notifications'); + } +} diff --git a/modules/Fediverse/Database/Migrations/2018-01-02-120000_update_activities_status.php b/modules/Fediverse/Database/Migrations/2018-01-02-120000_update_activities_status.php new file mode 100644 index 00000000..2d7adac0 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2018-01-02-120000_update_activities_status.php @@ -0,0 +1,44 @@ + [ + 'type' => 'ENUM', + 'constraint' => ['queued', 'processing', 'delivered', 'failed'], + 'null' => true, + ], + ]; + + $this->forge->modifyColumn('fediverse_activities', $fields); + } + + public function down(): void + { + $fields = [ + 'status' => [ + 'type' => 'ENUM', + 'constraint' => ['queued', 'delivered'], + 'null' => true, + ], + ]; + + $this->forge->modifyColumn('fediverse_activities', $fields); + } +} diff --git a/modules/Fediverse/Database/Migrations/2025-07-31-120000_add_is_private_to_posts.php b/modules/Fediverse/Database/Migrations/2025-07-31-120000_add_is_private_to_posts.php new file mode 100644 index 00000000..d1ac9327 --- /dev/null +++ b/modules/Fediverse/Database/Migrations/2025-07-31-120000_add_is_private_to_posts.php @@ -0,0 +1,35 @@ + [ + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, + 'after' => 'message_html', + ], + ]; + + $this->forge->addColumn('fediverse_posts', $fields); + } + + public function down(): void + { + $this->forge->dropColumn('fediverse_posts', 'is_private'); + } +} diff --git a/modules/Fediverse/Entities/Activity.php b/modules/Fediverse/Entities/Activity.php new file mode 100644 index 00000000..34d34cec --- /dev/null +++ b/modules/Fediverse/Entities/Activity.php @@ -0,0 +1,99 @@ + + */ + protected $dates = ['scheduled_at', 'created_at']; + + /** + * @var array + */ + protected $casts = [ + 'id' => 'string', + 'actor_id' => 'integer', + 'target_actor_id' => '?integer', + 'post_id' => '?string', + 'type' => 'string', + 'payload' => 'json', + 'status' => '?string', + ]; + + public function getActor(): Actor + { + if (! $this->actor instanceof Actor) { + $this->actor = model('ActorModel', false) + ->getActorById($this->actor_id); + } + + return $this->actor; + } + + public function getTargetActor(): Actor + { + if ($this->target_actor_id === null) { + throw new RuntimeException('Activity must have a target_actor_id before getting the target actor.'); + } + + if (! $this->target_actor instanceof Actor) { + $this->target_actor = model('ActorModel', false) + ->getActorById($this->target_actor_id); + } + + return $this->target_actor; + } + + public function getPost(): Post + { + if ($this->post_id === null) { + throw new RuntimeException('Activity must have a post_id before getting post.'); + } + + if (! $this->post instanceof Post) { + $this->post = model('PostModel', false) + ->getPostById($this->post_id); + } + + return $this->post; + } +} diff --git a/modules/Fediverse/Entities/Actor.php b/modules/Fediverse/Entities/Actor.php new file mode 100644 index 00000000..9b6bdb42 --- /dev/null +++ b/modules/Fediverse/Entities/Actor.php @@ -0,0 +1,141 @@ + + */ + protected $casts = [ + 'id' => 'integer', + 'uri' => 'string', + 'username' => 'string', + 'domain' => 'string', + 'display_name' => 'string', + 'summary' => '?string', + 'private_key' => '?string', + 'public_key' => '?string', + 'avatar_image_url' => '?string', + 'avatar_image_mimetype' => '?string', + 'cover_image_url' => '?string', + 'cover_image_mimetype' => '?string', + 'inbox_url' => 'string', + 'outbox_url' => '?string', + 'followers_url' => '?string', + 'followers_count' => 'integer', + 'posts_count' => 'integer', + 'is_blocked' => 'boolean', + ]; + + public function getPublicKeyId(): string + { + return $this->uri . '#main-key'; + } + + public function getIsLocal(): bool + { + if (! $this->is_local) { + $uri = current_url(true); + + $this->is_local = + $this->domain === + $uri->getHost() . + ($uri->getPort() ? ':' . $uri->getPort() : ''); + } + + return $this->is_local; + } + + /** + * @return Actor[] + */ + public function getFollowers(): array + { + if ($this->followers === null) { + $this->followers = model('ActorModel', false) + ->getFollowers($this->id); + } + + return $this->followers; + } + + public function getAvatarImageUrl(): string + { + if ($this->attributes['avatar_image_url'] === null) { + return base_url(config('Fediverse')->defaultAvatarImagePath); + } + + return $this->attributes['avatar_image_url']; + } + + public function getAvatarImageMimetype(): string + { + if ($this->attributes['avatar_image_mimetype'] === null) { + return config('Fediverse')->defaultAvatarImageMimetype; + } + + return $this->attributes['avatar_image_mimetype']; + } + + public function getCoverImageUrl(): string + { + if ($this->attributes['cover_image_url'] === null) { + return base_url(config('Fediverse')->defaultCoverImagePath); + } + + return $this->attributes['cover_image_url']; + } + + public function getCoverImageMimetype(): string + { + if ($this->attributes['cover_image_mimetype'] === null) { + return config('Fediverse')->defaultCoverImageMimetype; + } + + return $this->attributes['cover_image_mimetype']; + } +} diff --git a/app/Libraries/ActivityPub/Entities/BlockedDomain.php b/modules/Fediverse/Entities/BlockedDomain.php similarity index 84% rename from app/Libraries/ActivityPub/Entities/BlockedDomain.php rename to modules/Fediverse/Entities/BlockedDomain.php index ca495569..adf0ca8d 100644 --- a/app/Libraries/ActivityPub/Entities/BlockedDomain.php +++ b/modules/Fediverse/Entities/BlockedDomain.php @@ -3,12 +3,12 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Entities; +namespace Modules\Fediverse\Entities; use CodeIgniter\Entity\Entity; diff --git a/modules/Fediverse/Entities/Favourite.php b/modules/Fediverse/Entities/Favourite.php new file mode 100644 index 00000000..1811d8f5 --- /dev/null +++ b/modules/Fediverse/Entities/Favourite.php @@ -0,0 +1,33 @@ + + */ + protected $casts = [ + 'actor_id' => 'integer', + 'post_id' => 'string', + ]; +} diff --git a/app/Libraries/ActivityPub/Entities/Follow.php b/modules/Fediverse/Entities/Follow.php similarity index 78% rename from app/Libraries/ActivityPub/Entities/Follow.php rename to modules/Fediverse/Entities/Follow.php index 5eb57258..49736eea 100644 --- a/app/Libraries/ActivityPub/Entities/Follow.php +++ b/modules/Fediverse/Entities/Follow.php @@ -3,12 +3,12 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Entities; +namespace Modules\Fediverse\Entities; use CodeIgniter\Entity\Entity; @@ -22,7 +22,7 @@ class Follow extends Entity * @var array */ protected $casts = [ - 'actor_id' => 'integer', + 'actor_id' => 'integer', 'target_actor_id' => 'integer', ]; } diff --git a/modules/Fediverse/Entities/Notification.php b/modules/Fediverse/Entities/Notification.php new file mode 100644 index 00000000..0815c273 --- /dev/null +++ b/modules/Fediverse/Entities/Notification.php @@ -0,0 +1,99 @@ + + */ + protected $dates = ['read_at', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'id' => 'integer', + 'actor_id' => 'integer', + 'target_actor_id' => 'integer', + 'post_id' => '?string', + 'activity_id' => 'string', + 'type' => 'string', + ]; + + public function getActor(): ?Actor + { + if (! $this->actor instanceof Actor) { + $this->actor = new ActorModel() + ->getActorById($this->actor_id); + } + + return $this->actor; + } + + public function getTargetActor(): ?Actor + { + if (! $this->target_actor instanceof Actor) { + $this->target_actor = new ActorModel() + ->getActorById($this->target_actor_id); + } + + return $this->target_actor; + } + + public function getPost(): ?Post + { + if ($this->post_id === null) { + throw new RuntimeException('Notification must have a post_id before getting post.'); + } + + if (! $this->post instanceof Post) { + $this->post = new PostModel() + ->getPostById($this->post_id); + } + + return $this->post; + } +} diff --git a/modules/Fediverse/Entities/Post.php b/modules/Fediverse/Entities/Post.php new file mode 100644 index 00000000..10d41a2a --- /dev/null +++ b/modules/Fediverse/Entities/Post.php @@ -0,0 +1,185 @@ + + */ + protected $dates = ['published_at', 'created_at']; + + /** + * @var array + */ + protected $casts = [ + 'id' => 'string', + 'uri' => 'string', + 'actor_id' => 'integer', + 'in_reply_to_id' => '?string', + 'reblog_of_id' => '?string', + 'message' => 'string', + 'message_html' => 'string', + 'is_private' => 'boolean', + 'favourites_count' => 'integer', + 'reblogs_count' => 'integer', + 'replies_count' => 'integer', + ]; + + /** + * Returns the post's actor + */ + public function getActor(): Actor + { + if (! $this->actor instanceof Actor) { + $this->actor = model('ActorModel', false) + ->getActorById($this->actor_id); + } + + return $this->actor; + } + + public function getPreviewCard(): ?PreviewCard + { + if (! $this->preview_card instanceof PreviewCard) { + $this->preview_card = model('PreviewCardModel', false) + ->getPostPreviewCard($this->id); + } + + return $this->preview_card; + } + + /** + * @return Post[] + */ + public function getReplies(): array + { + if ($this->replies === null) { + $this->replies = model('PostModel', false) + ->getPostReplies($this->id); + } + + return $this->replies; + } + + public function getHasReplies(): bool + { + return $this->getReplies() !== []; + } + + public function getReplyToPost(): ?self + { + if ($this->in_reply_to_id === null) { + throw new RuntimeException('Post is not a reply.'); + } + + if (! $this->reply_to_post instanceof self) { + $this->reply_to_post = model('PostModel', false) + ->getPostById($this->in_reply_to_id); + } + + return $this->reply_to_post; + } + + /** + * @return Post[] + */ + public function getReblogs(): array + { + if ($this->reblogs === null) { + $this->reblogs = model('PostModel', false) + ->getPostReblogs($this->id); + } + + return $this->reblogs; + } + + public function getReblogOfPost(): ?self + { + if ($this->reblog_of_id === null) { + throw new RuntimeException('Post is not a reblog.'); + } + + if (! $this->reblog_of_post instanceof self) { + $this->reblog_of_post = model('PostModel', false) + ->getPostById($this->reblog_of_id); + } + + return $this->reblog_of_post; + } + + public function setMessage(string $message): static + { + helper('fediverse'); + + $messageWithoutTags = strip_tags($message); + + $this->attributes['message'] = $messageWithoutTags; + $this->attributes['message_html'] = str_replace("\n", '
    ', linkify($messageWithoutTags)); + + return $this; + } +} diff --git a/modules/Fediverse/Entities/PreviewCard.php b/modules/Fediverse/Entities/PreviewCard.php new file mode 100644 index 00000000..2271aca4 --- /dev/null +++ b/modules/Fediverse/Entities/PreviewCard.php @@ -0,0 +1,48 @@ + + */ + protected $casts = [ + 'id' => 'integer', + 'post_id' => 'string', + 'url' => 'string', + 'title' => 'string', + 'description' => 'string', + 'type' => 'string', + 'author_name' => '?string', + 'author_url' => '?string', + 'provider_name' => '?string', + 'provider_url' => '?string', + 'image' => '?string', + 'html' => '?string', + ]; +} diff --git a/modules/Fediverse/Filters/FediverseFilter.php b/modules/Fediverse/Filters/FediverseFilter.php new file mode 100644 index 00000000..2e9b32ba --- /dev/null +++ b/modules/Fediverse/Filters/FediverseFilter.php @@ -0,0 +1,89 @@ +media($allowedContentTypes) === '') { + throw PageNotFoundException::forPageNotFound(); + } + } + + if (in_array('verify-blocks', $params, true)) { + // @phpstan-ignore-next-line + $payload = $request->getJSON(); + + $actorUri = $payload->actor; + $domain = new URI($actorUri) + ->getHost(); + + // check first if domain is blocked + if (model('BlockedDomainModel', false)->isDomainBlocked($domain)) { + throw PageNotFoundException::forPageNotFound(); + } + + // check if actor is blocked + if (model('ActorModel', false)->isActorBlocked($actorUri)) { + throw PageNotFoundException::forPageNotFound(); + } + } + + log_message('critical', 'ITS HEEEEEEEEEEEERE'); + + if (in_array('verify-signature', $params, true)) { + try { + // securityCheck: check activity signature before handling it + new HttpSignature() + ->verify(); + } catch (Exception) { + // Invalid HttpSignature (401 = unauthorized) + // TODO: show error message? + return service('response')->setStatusCode(401); + } + } + + return null; + } + + /** + * @param string[]|null $arguments + * + * @return ResponseInterface|null + */ + #[Override] + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + return null; + } +} diff --git a/modules/Fediverse/Helpers/fediverse_helper.php b/modules/Fediverse/Helpers/fediverse_helper.php new file mode 100644 index 00000000..391842a8 --- /dev/null +++ b/modules/Fediverse/Helpers/fediverse_helper.php @@ -0,0 +1,519 @@ +setScheme('https'); + $webfingerUri->setHost($domain); + $webfingerUri->setPath('/.well-known/webfinger'); + $webfingerUri->setQuery("resource=acct:{$username}@{$domain}"); + + $webfingerRequest = new ActivityRequest((string) $webfingerUri); + $webfingerResponse = $webfingerRequest->get(); + + return json_decode((string) $webfingerResponse->getBody(), false, 512, JSON_THROW_ON_ERROR); + } +} + +if (! function_exists('split_handle')) { + /** + * Splits handle into its parts (username, host and port) + * + * @return array{0:string,username:non-empty-string,1:non-empty-string,domain:non-empty-string,2:non-empty-string,port?:non-falsy-string,3?:non-falsy-string} + */ + function split_handle(string $handle): array | false + { + if ( + ! preg_match('~^@?(?P[\w\.\-]+)@(?P[\w\.\-]+)(?P:[\d]+)?$~', $handle, $matches) + ) { + return false; + } + + return $matches; + } +} + +if (! function_exists('accept_follow')) { + /** + * Sends an accept activity to the targetActor's inbox + * + * @param Actor $actor Actor which accepts the follow + * @param Actor $targetActor Actor which receives the accept follow + */ + function accept_follow(Actor $actor, Actor $targetActor, string $objectId): void + { + $acceptActivity = new AcceptActivity(); + + $object = new ObjectType(); + $object->set('id', $objectId); + $object->set('type', 'Follow'); + $object->set('actor', $targetActor->uri); + $object->set('object', $actor->uri); + + $acceptActivity->set('actor', $actor->uri) + ->set('object', $object); + + $db = db_connect(); + $db->transStart(); + + $activityModel = model('ActivityModel', false); + $activityId = $activityModel->newActivity( + 'Accept', + $actor->id, + $targetActor->id, + null, + $acceptActivity->toJSON(), + ); + + $acceptActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + $activityModel->update($activityId, [ + 'payload' => $acceptActivity->toJSON(), + ]); + + try { + $acceptRequest = new ActivityRequest($targetActor->inbox_url, $acceptActivity->toJSON()); + $acceptRequest->sign($actor->public_key_id, $actor->private_key); + $acceptRequest->post(); + } catch (Exception) { + $db->transRollback(); + } + + $db->transComplete(); + } +} + +if (! function_exists('send_activity_to_actor')) { + /** + * Sends an activity to all actor followers + */ + function send_activity_to_actor(Actor $actor, Actor $targetActor, string $activityPayload): void + { + try { + $acceptRequest = new ActivityRequest($targetActor->inbox_url, $activityPayload); + if ($actor->private_key !== null) { + $acceptRequest->sign($actor->public_key_id, $actor->private_key); + } + + $acceptRequest->post(); + } catch (Exception $exception) { + // log error + log_message('critical', $exception->getMessage()); + } + } +} + +if (! function_exists('send_activity_to_followers')) { + /** + * Sends an activity to all actor followers + */ + function send_activity_to_followers(Actor $actor, string $activityPayload): void + { + // TODO: send activities in parallel with https://www.php.net/manual/en/function.curl-multi-init.php + foreach ($actor->followers as $follower) { + send_activity_to_actor($actor, $follower, $activityPayload); + } + } +} + +if (! function_exists('extract_urls_from_message')) { + /** + * Returns an array of all urls from a string + * + * @return string[] + */ + function extract_urls_from_message(string $message): array + { + preg_match_all('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?getUrlData((string) $url); + + if ($mediaData !== []) { + $mediaUrl = array_key_first($mediaData); + $media = array_first($mediaData); + + if (array_key_exists('title', $media)) { + $typeMapping = [ + 'photo' => 'image', + 'video' => 'video', + 'website' => 'link', + 'rich' => 'rich', + ]; + + // Check that, at least, the url and title are set + $newPreviewCard = new PreviewCard([ + 'url' => $mediaUrl, + 'title' => $media['title'] ?? '', + 'description' => $media['description'] ?? '', + 'type' => $typeMapping[$media['type']] ?? 'link', + 'author_name' => $media['author_name'] ?? null, + 'author_url' => $media['author_url'] ?? null, + 'provider_name' => $media['provider_name'] ?? '', + 'provider_url' => $media['provider_url'] ?? '', + 'image' => $media['thumbnail_url'] ?? '', + 'html' => $media['html'] ?? '', + ]); + + if ( + ! ($newPreviewCardId = model('PreviewCardModel', false)->insert($newPreviewCard, true)) + ) { + return null; + } + + $newPreviewCard->id = $newPreviewCardId; + return $newPreviewCard; + } + } + + return null; + } +} + +if (! function_exists('get_or_create_preview_card_from_url')) { + /** + * Extract open graph metadata from given url and create preview card + */ + function get_or_create_preview_card_from_url(URI $url): ?PreviewCard + { + // check if preview card has already been generated + if ( + ($previewCard = model('PreviewCardModel', false) + ->getPreviewCardFromUrl((string) $url)) instanceof PreviewCard + ) { + return $previewCard; + } + + // create preview card + return create_preview_card_from_url($url); + } +} + +if (! function_exists('get_or_create_actor_from_uri')) { + /** + * Retrieves actor from database using the actor uri If Actor is not present, it creates the record in the database + * and returns it. + */ + function get_or_create_actor_from_uri(string $actorUri): ?Actor + { + // check if actor exists in database already and return it + if (($actor = model('ActorModel', false)->getActorByUri($actorUri)) instanceof Actor) { + return $actor; + } + + // if the actor doesn't exist, request actorUri to create it + return create_actor_from_uri($actorUri); + } +} + +if (! function_exists('get_or_create_actor')) { + /** + * Retrieves actor from database using the actor username and domain If actor is not present, it creates the record + * in the database and returns it. + */ + function get_or_create_actor(string $username, string $domain): ?Actor + { + // check if actor exists in database already and return it + if ( + ($actor = model('ActorModel', false) + ->getActorByUsername($username, $domain)) instanceof Actor + ) { + return $actor; + } + + // get actorUri with webfinger request + $webfingerData = get_webfinger_data($username, $domain); + $actorUriKey = array_search('self', array_column($webfingerData->links, 'rel'), true); + + return create_actor_from_uri($webfingerData->links[$actorUriKey]->href); + } +} + +if (! function_exists('create_actor_from_uri')) { + /** + * Creates actor record in database using the info gathered from the actorUri parameter + */ + function create_actor_from_uri(string $actorUri): ?Actor + { + $activityRequest = new ActivityRequest($actorUri); + $actorResponse = $activityRequest->get(); + $actorPayload = json_decode((string) $actorResponse->getBody(), false, 512, JSON_THROW_ON_ERROR); + + $newActor = new Actor(); + $newActor->uri = $actorUri; + $newActor->username = $actorPayload->preferredUsername; + $newActor->domain = $activityRequest->getDomain(); + $newActor->public_key = $actorPayload->publicKey->publicKeyPem; + $newActor->private_key = null; + $newActor->display_name = $actorPayload->name; + $newActor->summary = property_exists($actorPayload, 'summary') ? $actorPayload->summary : null; + if (property_exists($actorPayload, 'icon')) { + $newActor->avatar_image_url = $actorPayload->icon->url; + + if (property_exists($actorPayload->icon, 'mediaType')) { + $newActor->avatar_image_mimetype = $actorPayload->icon->mediaType; + } else { + $iconExtension = pathinfo((string) $actorPayload->icon->url, PATHINFO_EXTENSION); + + $newActor->avatar_image_mimetype = (string) Mimes::guessTypeFromExtension($iconExtension); + } + } + + if (property_exists($actorPayload, 'image')) { + $newActor->cover_image_url = $actorPayload->image->url; + + if (property_exists($actorPayload->image, 'mediaType')) { + $newActor->cover_image_mimetype = $actorPayload->image->mediaType; + } else { + $coverExtension = pathinfo((string) $actorPayload->image->url, PATHINFO_EXTENSION); + + $newActor->cover_image_mimetype = (string) Mimes::guessTypeFromExtension($coverExtension); + } + } + + $newActor->inbox_url = $actorPayload->inbox; + $newActor->outbox_url = property_exists($actorPayload, 'outbox') ? $actorPayload->outbox : null; + $newActor->followers_url = property_exists($actorPayload, 'followers') ? $actorPayload->followers : null; + + if (! ($newActorId = model('ActorModel', false)->insert($newActor, true))) { + return null; + } + + $newActor->id = $newActorId; + return $newActor; + } +} + +if (! function_exists('get_current_domain')) { + /** + * Returns instance's domain name + */ + function get_current_domain(): string + { + $uri = current_url(true); + return $uri->getHost() . ($uri->getPort() ? ':' . $uri->getPort() : ''); + } +} + +if (! function_exists('extract_text_from_html')) { + /** + * Extracts the text from html content + */ + function extract_text_from_html(string $content): ?string + { + return preg_replace('~\s+~', ' ', strip_tags($content)); + } +} + +if (! function_exists('get_message_from_object')) { + /** + * Gets the message from content, if no content key is present, checks for content in contentMap + * + * TODO: store multiple languages, convert markdown + */ + function get_message_from_object(stdClass $object): string | false + { + if (property_exists($object, 'content') && is_string($object->content)) { + extract_text_from_html($object->content); + return $object->content; + } + + $message = ''; + if (property_exists($object, 'contentMap')) { + // TODO: update message to be json? (include all languages?) + if (property_exists($object->contentMap, 'en')) { + extract_text_from_html($object->contentMap->en); + $message = $object->contentMap->en; + } else { + $message = current($object->contentMap); + } + } + + return $message; + } +} + +if (! function_exists('is_note_public')) { + /** + * Check whether note is public or not + */ + function is_note_public(stdClass $object): bool + { + $isPublic = false; + if (property_exists($object, 'to') && is_array($object->to)) { + $isPublic = in_array('https://www.w3.org/ns/activitystreams#Public', $object->to, true); + } + + if ($isPublic) { + return true; + } + + if (property_exists($object, 'cc') && is_array($object->cc)) { + return in_array('https://www.w3.org/ns/activitystreams#Public', $object->cc, true); + } + + return $isPublic; + } +} + +if (! function_exists('linkify')) { + /** + * Turn all link elements in clickable links. Transforms urls and handles + * + * @param string[] $protocols http/https, twitter + */ + function linkify(string $text, array $protocols = ['http', 'handle']): string + { + $links = []; + + // Extract text links for each protocol + foreach ($protocols as $protocol) { + $text = match ($protocol) { + 'http', 'https' => preg_replace_callback( + '~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(? '_blank', + 'rel' => 'noopener noreferrer', + ], + ), + ) . + '>'; + }, + (string) $text, + ), + 'handle' => preg_replace_callback( + '~(?\w++)(?:@(?(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]))?~', + static function (array $match) use (&$links): string { + // check if host is set and look for actor in database + if (isset($match['domain'])) { + if ( + ($actor = model( + 'ActorModel', + )->getActorByUsername($match['username'], $match['domain'])) instanceof Actor + ) { + // TODO: check that host is local to remove target blank? + return '<' . + array_push( + $links, + anchor($actor->uri, $match[0], [ + 'target' => '_blank', + 'rel' => 'noopener noreferrer', + ]), + ) . + '>'; + } + + try { + $actor = get_or_create_actor($match['username'], $match['domain']); + return '<' . + array_push( + $links, + anchor($actor->uri, $match[0], [ + 'target' => '_blank', + 'rel' => 'noopener noreferrer', + ]), + ) . + '>'; + } catch (HTTPException) { + // Couldn't retrieve actor, do not wrap the text in link + return '<' . + array_push($links, $match[0]) . + '>'; + } + } else { + if ( + ($actor = model('ActorModel', false) + ->getActorByUsername($match['username'])) instanceof Actor + ) { + return '<' . + array_push($links, anchor($actor->uri, $match[0])) . + '>'; + } + + return '<' . + array_push($links, $match[0]) . + '>'; + } + }, + (string) $text, + ), + default => preg_replace_callback( + '~' . + preg_quote($protocol, '~') . + '://([^\s<]+?)(? '_blank', + 'rel' => 'noopener noreferrer', + ], + ), + ) . + '>'; + }, + (string) $text, + ), + }; + } + + // Insert all links + return preg_replace_callback( + '~<(\d+)>~', + static function (array $match) use (&$links): string { + return $links[(int) $match[1] - 1]; + }, + (string) $text, + ); + } +} diff --git a/modules/Fediverse/HttpSignature.php b/modules/Fediverse/HttpSignature.php new file mode 100644 index 00000000..145f0848 --- /dev/null +++ b/modules/Fediverse/HttpSignature.php @@ -0,0 +1,179 @@ +https?:\/\/[\w\-\.]+[\w]+(:[\d]+)?[\w\-\.#\/@]+)")) + (?=.*(signature="(?P[\w+\/]+={0,2})")) + (?=.*(headers="\(request-target\)(?P[\w\\-\s]+)"))? + (?=.*(algorithm="(?P[\w\-]+)"))? + /x'; + + protected IncomingRequest $request; + + public function __construct(?IncomingRequest $request = null) + { + if (! $request instanceof IncomingRequest) { + $request = service('request'); + } + + $this->request = $request; + } + + /** + * Verify an incoming message based upon its HTTP signature + * + * @return bool True if signature has been verified. Otherwise false + */ + public function verify(): bool + { + if (! ($dateHeader = $this->request->header('date'))) { + throw new Exception('Request must include a date header.'); + } + + // verify that request has been made within the last hour + $currentTime = Time::now(); + $requestTime = Time::createFromFormat('D, d M Y H:i:s T', $dateHeader->getValue()); + + $diff = $requestTime->difference($currentTime); + $diffSeconds = $diff->getSeconds(); + if ($diffSeconds > 3600 || $diffSeconds < 0) { + throw new Exception('Request must be made within the last hour.'); + } + + // check that digest header is set + if (! ($digestHeader = $this->request->header('digest'))) { + throw new Exception('Request must include a digest header'); + } + + // compute body digest and compare with header digest + $bodyDigest = hash('sha256', (string) $this->request->getBody(), true); + $digest = 'SHA-256=' . base64_encode($bodyDigest); + if ($digest !== $digestHeader->getValue()) { + throw new Exception('Request digest is incorrect.'); + } + + // read the Signature header + if (($signature = $this->request->getHeaderLine('signature')) === '') { + // Signature header not found + throw new Exception('Request must include a signature header'); + } + + // Split it into its parts (keyId, headers and signature) + if (! ($parts = $this->splitSignature($signature))) { + throw new Exception('Malformed signature string.'); + } + + // set $keyId, $headers and $signature variables + $keyId = $parts['keyId']; + $algorithm = $parts['algorithm']; + $headers = $parts['headers'] ?? 'date'; + $signature = $parts['signature']; + + // Fetch the public key linked from keyId + $actorRequest = new ActivityRequest($keyId); + $actorResponse = $actorRequest->get(); + $actor = json_decode((string) $actorResponse->getBody(), false, 512, JSON_THROW_ON_ERROR); + + $publicKeyPem = (string) $actor->publicKey->publicKeyPem; + + // Create a comparison string from the plaintext headers we got + // in the same order as was given in the signature header, + $data = $this->getPlainText(explode(' ', trim($headers))); + + // Verify the data string using the public key and the original signature. + return $this->verifySignature($publicKeyPem, $data, $signature, $algorithm); + } + + /** + * Split HTTP signature into its parts (keyId, headers and signature) + * + * @return array|false + */ + private function splitSignature(string $signature): bool|array + { + if (! preg_match(self::SIGNATURE_PATTERN, $signature, $matches, PREG_UNMATCHED_AS_NULL)) { + // Signature pattern failed + return false; + } + + // Headers are optional + if (! isset($matches['headers']) || $matches['headers'] === '') { + $matches['headers'] = 'date'; + } + + return $matches; + } + + /** + * Get plain text that has been originally signed + * + * @param string[] $headers HTTP header keys + */ + private function getPlainText(array $headers): string + { + $strings = []; + $strings[] = sprintf( + '(request-target): %s %s%s', + $this->request->getMethod(), + '/' . $this->request->getUri()->getPath(), + $this->request->getUri() + ->getQuery() !== '' + ? '?' . $this->request->getUri()->getQuery() + : '', + ); + + foreach ($headers as $key) { + if ($this->request->hasHeader($key)) { + $strings[] = "{$key}: {$this->request->getHeaderLine($key)}"; + } + } + + return implode("\n", $strings); + } + + /** + * Verifies the signature depending on the algorithm sent + */ + private function verifySignature( + string $publicKeyPem, + string $data, + string $signature, + string $algorithm = 'rsa-sha256', + ): bool { + if ($algorithm === 'rsa-sha512' || $algorithm === 'rsa-sha256') { + $hash = substr($algorithm, strpos($algorithm, '-') + 1); + $rsa = new RSA(); + $rsa->setHash($hash); + $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); + $rsa->loadKey($publicKeyPem); + + return $rsa->verify($data, (string) base64_decode($signature, true)); + } + + // not implemented + return false; + } +} diff --git a/modules/Fediverse/Models/ActivityModel.php b/modules/Fediverse/Models/ActivityModel.php new file mode 100644 index 00000000..21cd5538 --- /dev/null +++ b/modules/Fediverse/Models/ActivityModel.php @@ -0,0 +1,207 @@ + + */ + protected $afterInsert = ['notify']; + + /** + * @var list + */ + protected $afterUpdate = ['notify']; + + /** + * @var list + */ + protected $allowedFields = [ + 'id', + 'actor_id', + 'target_actor_id', + 'post_id', + 'type', + 'payload', + 'status', + 'scheduled_at', + ]; + + /** + * @var class-string + */ + protected $returnType = Activity::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + protected $updatedField = ''; + + public function getActivityById(string $activityId): ?Activity + { + $cacheName = + config('Fediverse') + ->cachePrefix . "activity#{$activityId}"; + if (! ($found = cache($cacheName))) { + $found = $this->find($activityId); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Inserts a new activity record in the database + * + * @param Time|null $scheduledAt + */ + public function newActivity( + string $type, + int $actorId, + ?int $targetActorId, + ?string $postId, + string $payload, + ?DateTimeInterface $scheduledAt = null, + ?string $taskStatus = null, + ): BaseResult | int | string | false { + return $this->insert( + [ + 'actor_id' => $actorId, + 'target_actor_id' => $targetActorId, + 'post_id' => $postId, + 'type' => $type === 'Undo' ? $type . '_' . (json_decode( + $payload, + true, + ))['object']['type'] : $type, + 'payload' => $payload, + 'scheduled_at' => $scheduledAt, + 'status' => $taskStatus, + ], + true, + ); + } + + /** + * @return Activity[] + */ + public function getScheduledActivities(int $limit = 10): array + { + return $this->where('`scheduled_at` <= UTC_TIMESTAMP()', null, false) + ->where('status', 'queued') + ->orderBy('scheduled_at', 'ASC') + ->limit($limit) + ->findAll(); + } + + /** + * @param array $data + * @return array> + */ + protected function notify(array $data): array + { + /** @var ?Activity $activity */ + $activity = new self() + ->find(is_array($data['id']) ? $data['id'][0] : $data['id']); + + if (! $activity instanceof Activity) { + return $data; + } + + if ($activity->target_actor_id === $activity->actor_id) { + return $data; + } + + // notify only if incoming activity (with status set to NULL) is created + if ($activity->status !== null) { + return $data; + } + + if ($activity->type === 'Follow') { + new NotificationModel() + ->insert([ + 'actor_id' => $activity->actor_id, + 'target_actor_id' => $activity->target_actor_id, + 'activity_id' => $activity->id, + 'type' => 'follow', + 'created_at' => $activity->created_at, + ]); + } elseif ($activity->type === 'Undo_Follow') { + new NotificationModel() + ->builder() + ->delete([ + 'actor_id' => $activity->actor_id, + 'target_actor_id' => $activity->target_actor_id, + 'type' => 'follow', + ]); + } elseif (in_array($activity->type, ['Create', 'Like', 'Announce'], true) && $activity->post_id !== null) { + new NotificationModel() + ->insert([ + 'actor_id' => $activity->actor_id, + 'target_actor_id' => $activity->target_actor_id, + 'post_id' => $activity->post_id, + 'activity_id' => $activity->id, + 'type' => match ($activity->type) { + 'Create' => 'reply', + 'Like' => 'like', + 'Announce' => 'share', + }, + 'created_at' => $activity->created_at, + ]); + } elseif (in_array($activity->type, ['Undo_Like', 'Undo_Announce'], true) && $activity->post_id !== null) { + new NotificationModel() + ->builder() + ->delete([ + 'actor_id' => $activity->actor_id, + 'target_actor_id' => $activity->target_actor_id, + 'post_id' => service('uuid') + ->fromString($activity->post_id) + ->getBytes(), + 'type' => match ($activity->type) { + 'Undo_Like' => 'like', + 'Undo_Announce' => 'share', + }, + ]); + } + + return $data; + } +} diff --git a/modules/Fediverse/Models/ActorModel.php b/modules/Fediverse/Models/ActorModel.php new file mode 100644 index 00000000..c061e11d --- /dev/null +++ b/modules/Fediverse/Models/ActorModel.php @@ -0,0 +1,313 @@ + + */ + protected $allowedFields = [ + 'id', + 'uri', + 'username', + 'domain', + 'display_name', + 'summary', + 'private_key', + 'public_key', + 'avatar_image_url', + 'avatar_image_mimetype', + 'cover_image_url', + 'cover_image_mimetype', + 'inbox_url', + 'outbox_url', + 'followers_url', + 'followers_count', + 'posts_count', + 'is_blocked', + ]; + + /** + * @var class-string + */ + protected $returnType = Actor::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + public function getActorById(int $id): ?Actor + { + return $this->find($id); + } + + /** + * Looks for actor with username and domain, if no domain has been specified, the current host will be used + */ + public function getActorByUsername(string $username, ?string $domain = null): ?Actor + { + // TODO: is there a better way? + helper('fediverse'); + + if (! $domain) { + $domain = get_current_domain(); + } + + // remove colons for port if set + $cacheDomain = str_replace(':', '', $domain); + + $cacheName = "actor-{$username}-{$cacheDomain}"; + if (! ($found = cache($cacheName))) { + $found = $this->where([ + 'username' => $username, + 'domain' => $domain, + ])->first(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function getActorByUri(string $actorUri): ?Actor + { + $hashedActorUri = md5($actorUri); + $cacheName = + config('Fediverse') + ->cachePrefix . "actor-{$hashedActorUri}"; + if (! ($found = cache($cacheName))) { + $found = $this->where('uri', $actorUri) + ->first(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @return Actor[] + */ + public function getFollowers(int $actorId): array + { + $cacheName = + config('Fediverse') + ->cachePrefix . "actor#{$actorId}_followers"; + if (! ($found = cache($cacheName))) { + $found = $this->join('fediverse_follows', 'fediverse_follows.actor_id = id', 'inner') + ->where('fediverse_follows.target_actor_id', $actorId) + ->findAll(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Check if an existing actor is blocked using its uri. Returns FALSE if the actor doesn't exist + */ + public function isActorBlocked(string $actorUri): bool + { + if (($actor = $this->getActorByUri($actorUri)) instanceof Actor) { + return $actor->is_blocked; + } + + return false; + } + + /** + * Retrieves all blocked actors. + * + * @return Actor[] + */ + public function getBlockedActors(): array + { + $cacheName = config('Fediverse') + ->cachePrefix . 'blocked_actors'; + if (! ($found = cache($cacheName))) { + $found = $this->where('is_blocked', 1) + ->findAll(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function blockActor(int $actorId): void + { + $prefix = config('Fediverse') + ->cachePrefix; + cache() + ->delete($prefix . 'blocked_actors'); + cache() + ->deleteMatching($prefix . '*replies'); + + $this->update($actorId, [ + 'is_blocked' => 1, + ]); + + Events::trigger('on_block_actor', $actorId); + } + + public function unblockActor(int $actorId): void + { + $prefix = config('Fediverse') + ->cachePrefix; + cache() + ->delete($prefix . 'blocked_actors'); + cache() + ->deleteMatching($prefix . '*replies'); + + $this->update($actorId, [ + 'is_blocked' => 0, + ]); + + Events::trigger('on_unblock_actor', $actorId); + } + + public function getTotalLocalActors(): int + { + helper('fediverse'); + + $cacheName = config('Fediverse') + ->cachePrefix . 'blocked_actors'; + if (! ($found = cache($cacheName))) { + $result = $this->builder() + ->select('COUNT(*) as total_local_actors') + ->where('domain', get_current_domain()) + ->get() + ->getResultArray(); + + $found = (int) $result[0]['total_local_actors']; + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function getActiveLocalActors(int $lastNumberOfMonths = 1): int + { + helper('fediverse'); + + $cacheName = config('Fediverse') + ->cachePrefix . 'blocked_actors'; + if (! ($found = cache($cacheName))) { + $tablePrefix = config('Database') + ->default['DBPrefix']; + $result = $this->builder() + ->select('COUNT(DISTINCT `' . $tablePrefix . 'fediverse_actors`.`id`) as `total_active_actors`', false) + ->join( + $tablePrefix . 'fediverse_posts', + $tablePrefix . 'fediverse_actors.id = ' . $tablePrefix . 'fediverse_posts.actor_id', + 'left outer', + ) + ->join( + $tablePrefix . 'fediverse_favourites', + $tablePrefix . 'fediverse_actors.id = ' . $tablePrefix . 'fediverse_favourites.actor_id', + 'left outer', + ) + ->where($tablePrefix . 'fediverse_actors.domain', get_current_domain()) + ->groupStart() + ->where( + "`{$tablePrefix}fediverse_posts`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", + null, + false, + ) + ->orWhere( + "`{$tablePrefix}fediverse_favourites`.`created_at` >= UTC_TIMESTAMP() - INTERVAL {$lastNumberOfMonths} month", + null, + false, + ) + ->groupEnd() + ->get() + ->getResultArray(); + + $found = (int) $result[0]['total_active_actors']; + + cache() + ->save($cacheName, $found, DAY); + } + + return $found; + } + + public function resetFollowersCount(): int | false + { + $actorsFollowersCount = $this->db->table('fediverse_follows') + ->select('target_actor_id as id, COUNT(*) as `followers_count`') + ->groupBy('id') + ->get() + ->getResultArray(); + + if ($actorsFollowersCount !== []) { + return $this->updateBatch($actorsFollowersCount, 'id'); + } + + return 0; + } + + public function resetPostsCount(): int | false + { + $actorsFollowersCount = $this->db->table('fediverse_posts') + ->select('actor_id as id, COUNT(*) as `posts_count`') + ->where([ + 'in_reply_to_id' => null, + ]) + ->groupBy('actor_id') + ->get() + ->getResultArray(); + + if ($actorsFollowersCount !== []) { + return $this->updateBatch($actorsFollowersCount, 'id'); + } + + return 0; + } + + public function clearCache(Actor $actor): void + { + $cachePrefix = config('Fediverse') + ->cachePrefix; + $hashedActorUri = md5($actor->uri); + $cacheDomain = str_replace(':', '', $actor->domain); + + cache() + ->delete($cachePrefix . "actor-{$actor->username}-{$cacheDomain}"); + cache() + ->delete($cachePrefix . "actor-{$hashedActorUri}"); + cache() + ->deleteMatching($cachePrefix . "actor#{$actor->id}*"); + } +} diff --git a/app/Libraries/ActivityPub/Models/BlockedDomainModel.php b/modules/Fediverse/Models/BlockedDomainModel.php similarity index 85% rename from app/Libraries/ActivityPub/Models/BlockedDomainModel.php rename to modules/Fediverse/Models/BlockedDomainModel.php index d5a3cccc..3b8acf3f 100644 --- a/app/Libraries/ActivityPub/Models/BlockedDomainModel.php +++ b/modules/Fediverse/Models/BlockedDomainModel.php @@ -3,24 +3,24 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Models; +namespace Modules\Fediverse\Models; -use ActivityPub\Entities\BlockedDomain; use CodeIgniter\Database\BaseResult; use CodeIgniter\Events\Events; use CodeIgniter\Model; +use Modules\Fediverse\Entities\BlockedDomain; class BlockedDomainModel extends Model { /** * @var string */ - protected $table = 'activitypub_blocked_domains'; + protected $table = 'fediverse_blocked_domains'; /** * @var string @@ -28,12 +28,12 @@ class BlockedDomainModel extends Model protected $primaryKey = 'name'; /** - * @var string[] + * @var list */ protected $allowedFields = ['name']; /** - * @var string + * @var class-string */ protected $returnType = BlockedDomain::class; @@ -47,7 +47,7 @@ class BlockedDomainModel extends Model */ protected $useTimestamps = true; - protected $updatedField; + protected $updatedField = ''; /** * Retrieves instance or podcast domain blocks depending on whether or not $podcastId param is set. @@ -56,7 +56,7 @@ class BlockedDomainModel extends Model */ public function getBlockedDomains(): array { - $cacheName = config('ActivityPub') + $cacheName = config('Fediverse') ->cachePrefix . 'blocked_domains'; if (! ($found = cache($cacheName))) { $found = $this->findAll(); @@ -64,6 +64,7 @@ class BlockedDomainModel extends Model cache() ->save($cacheName, $found, DECADE); } + return $found; } @@ -71,7 +72,7 @@ class BlockedDomainModel extends Model { $hashedDomainName = md5($name); $cacheName = - config('ActivityPub') + config('Fediverse') ->cachePrefix . "domain#{$hashedDomainName}_isBlocked"; if (! ($found = cache($cacheName))) { @@ -87,7 +88,7 @@ class BlockedDomainModel extends Model public function blockDomain(string $name): int | bool { $hashedDomain = md5($name); - $prefix = config('ActivityPub') + $prefix = config('Fediverse') ->cachePrefix; cache() ->delete($prefix . "domain#{$hashedDomain}_isBlocked"); @@ -100,7 +101,7 @@ class BlockedDomainModel extends Model $this->db->transStart(); // set all actors from the domain as blocked - model('ActorModel') + model('ActorModel', false) ->where('domain', $name) ->set('is_blocked', '1') ->update(); @@ -119,7 +120,7 @@ class BlockedDomainModel extends Model public function unblockDomain(string $name): BaseResult | bool { $hashedDomain = md5($name); - $prefix = config('ActivityPub') + $prefix = config('Fediverse') ->cachePrefix; cache() ->delete($prefix . "domain#{$hashedDomain}_isBlocked"); @@ -131,7 +132,7 @@ class BlockedDomainModel extends Model $this->db->transStart(); // unblock all actors from the domain - model('ActorModel') + model('ActorModel', false) ->where('domain', $name) ->set('is_blocked', '0') ->update(); diff --git a/modules/Fediverse/Models/FavouriteModel.php b/modules/Fediverse/Models/FavouriteModel.php new file mode 100644 index 00000000..0c1dfc6f --- /dev/null +++ b/modules/Fediverse/Models/FavouriteModel.php @@ -0,0 +1,181 @@ + + */ + protected $allowedFields = ['actor_id', 'post_id']; + + /** + * @var class-string + */ + protected $returnType = Favourite::class; + + /** + * @var bool + */ + protected $useTimestamps = true; + + protected $updatedField = ''; + + public function addFavourite(Actor $actor, Post $post, bool $registerActivity = true): void + { + $this->db->transStart(); + + $this->insert([ + 'actor_id' => $actor->id, + 'post_id' => $post->id, + ]); + + model('PostModel', false) + ->builder() + ->where('id', service('uuid') ->fromString($post->id) ->getBytes()) + ->increment('favourites_count'); + + if ($registerActivity) { + $likeActivity = new LikeActivity(); + $likeActivity->set('actor', $actor->uri) + ->set('object', $post->uri); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Like', + $actor->id, + $post->actor_id, + $post->id, + $likeActivity->toJSON(), + $post->published_at, + 'queued', + ); + + $likeActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $likeActivity->toJSON(), + ]); + } + + Events::trigger('on_post_favourite', $actor, $post); + + model('PostModel', false) + ->clearCache($post); + + $this->db->transComplete(); + } + + public function removeFavourite(Actor $actor, Post $post, bool $registerActivity = true): void + { + $this->db->transStart(); + + model('PostModel', false) + ->builder() + ->where('id', service('uuid') ->fromString($post->id) ->getBytes()) + ->decrement('favourites_count'); + + $this->where([ + 'actor_id' => $actor->id, + 'post_id' => service('uuid') + ->fromString($post->id) + ->getBytes(), + ]) + ->delete(); + + if ($registerActivity) { + $undoActivity = new UndoActivity(); + // get like activity + $activity = model('ActivityModel', false) + ->where([ + 'type' => 'Like', + 'actor_id' => $actor->id, + 'post_id' => service('uuid') + ->fromString($post->id) + ->getBytes(), + ]) + ->first(); + + $likeActivity = new LikeActivity(); + $likeActivity + ->set('id', url_to('activity', esc($actor->username), $activity->id)) + ->set('actor', $actor->uri) + ->set('object', $post->uri); + + $undoActivity + ->set('actor', $actor->uri) + ->set('object', $likeActivity); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Undo', + $actor->id, + $post->actor_id, + $post->id, + $undoActivity->toJSON(), + $post->published_at, + 'queued', + ); + + $undoActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $undoActivity->toJSON(), + ]); + } + + Events::trigger('on_post_undo_favourite', $actor, $post); + + model('PostModel', false) + ->clearCache($post); + + $this->db->transComplete(); + } + + /** + * Adds or removes favourite from database + */ + public function toggleFavourite(Actor $actor, Post $post): void + { + if ( + $this->where([ + 'actor_id' => $actor->id, + 'post_id' => service('uuid') + ->fromString($post->id) + ->getBytes(), + ])->first() instanceof Favourite + ) { + $this->removeFavourite($actor, $post); + } else { + $this->addFavourite($actor, $post); + } + } +} diff --git a/modules/Fediverse/Models/FollowModel.php b/modules/Fediverse/Models/FollowModel.php new file mode 100644 index 00000000..9541625a --- /dev/null +++ b/modules/Fediverse/Models/FollowModel.php @@ -0,0 +1,163 @@ + + */ + protected $allowedFields = ['actor_id', 'target_actor_id']; + + /** + * @var class-string + */ + protected $returnType = Follow::class; + + /** + * @var bool + */ + protected $useTimestamps = true; + + protected $updatedField = ''; + + /** + * @param Actor $actor Actor that is following + * @param Actor $targetActor Actor that is being followed + */ + public function addFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void + { + try { + $this->db->transStart(); + + $this->insert([ + 'actor_id' => $actor->id, + 'target_actor_id' => $targetActor->id, + ]); + + // increment followers_count for target actor + model('ActorModel', false) + ->builder() + ->where('id', $targetActor->id) + ->increment('followers_count'); + + if ($registerActivity) { + $followActivity = new FollowActivity(); + + $followActivity + ->set('actor', $actor->uri) + ->set('object', $targetActor->uri); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Follow', + $actor->id, + $targetActor->id, + null, + $followActivity->toJSON(), + Time::now(), + 'queued', + ); + + $followActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $followActivity->toJSON(), + ]); + } + + Events::trigger('on_follow', $actor, $targetActor); + + model('ActorModel', false) + ->clearCache($targetActor); + + $this->db->transComplete(); + } catch (Exception) { + // follow already exists, do nothing + } + } + + /** + * @param Actor $actor Actor that is unfollowing + * @param Actor $targetActor Actor that is being unfollowed + */ + public function removeFollower(Actor $actor, Actor $targetActor, bool $registerActivity = true): void + { + $this->db->transStart(); + + $this->where([ + 'actor_id' => $actor->id, + 'target_actor_id' => $targetActor->id, + ])->delete(); + + // decrement followers_count for target actor + model('ActorModel', false) + ->builder() + ->where('id', $targetActor->id) + ->decrement('followers_count'); + + if ($registerActivity) { + $undoActivity = new UndoActivity(); + // get follow activity from database + $followActivity = model('ActivityModel', false) + ->where([ + 'type' => 'Follow', + 'actor_id' => $actor->id, + 'target_actor_id' => $targetActor->id, + ]) + ->first(); + + $undoActivity + ->set('actor', $actor->uri) + ->set('object', $followActivity->payload); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Undo', + $actor->id, + $targetActor->id, + null, + $undoActivity->toJSON(), + Time::now(), + 'queued', + ); + + $undoActivity->set('id', url_to('activity', esc($actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $undoActivity->toJSON(), + ]); + } + + Events::trigger('on_undo_follow', $actor, $targetActor); + + model('ActorModel', false) + ->clearCache($targetActor); + + $this->db->transComplete(); + } +} diff --git a/modules/Fediverse/Models/NotificationModel.php b/modules/Fediverse/Models/NotificationModel.php new file mode 100644 index 00000000..b0993d6e --- /dev/null +++ b/modules/Fediverse/Models/NotificationModel.php @@ -0,0 +1,56 @@ + + */ + protected $returnType = Notification::class; + + /** + * @var bool + */ + protected $useTimestamps = true; + + /** + * @var string[] + */ + protected $uuidFields = ['post_id', 'activity_id']; + + /** + * @var list + */ + protected $allowedFields = [ + 'actor_id', + 'target_actor_id', + 'post_id', + 'activity_id', + 'type', + 'read_at', + 'created_at', + 'updated_at', + ]; +} diff --git a/modules/Fediverse/Models/PostModel.php b/modules/Fediverse/Models/PostModel.php new file mode 100644 index 00000000..e24000cc --- /dev/null +++ b/modules/Fediverse/Models/PostModel.php @@ -0,0 +1,735 @@ + + */ + protected $allowedFields = [ + 'id', + 'uri', + 'actor_id', + 'in_reply_to_id', + 'reblog_of_id', + 'message', + 'message_html', + 'is_private', + 'favourites_count', + 'reblogs_count', + 'replies_count', + 'published_at', + ]; + + /** + * @var class-string + */ + protected $returnType = Post::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + protected $updatedField = ''; + + /** + * @var array + */ + protected $validationRules = [ + 'actor_id' => 'required', + 'message_html' => 'max_length[500]', + ]; + + /** + * @var list + */ + protected $beforeInsert = ['setPostId']; + + public function getPostById(string $postId): ?Post + { + return $this->find($postId); + } + + public function getPostByUri(string $postUri): ?Post + { + $hashedPostUri = md5($postUri); + $cacheName = + config('Fediverse') + ->cachePrefix . "post-{$hashedPostUri}"; + if (! ($found = cache($cacheName))) { + $found = $this->where('uri', $postUri) + ->first(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Retrieves all published posts for a given actor ordered by publication date + * + * @return Post[] + */ + public function getActorPublishedPosts(int $actorId): array + { + $cacheName = + config('Fediverse') + ->cachePrefix . + "actor#{$actorId}_published_posts"; + if (! ($found = cache($cacheName))) { + $found = $this->where([ + 'actor_id' => $actorId, + 'in_reply_to_id' => null, + ]) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'DESC') + ->findAll(); + + $secondsToNextUnpublishedPost = $this->getSecondsToNextUnpublishedPosts($actorId); + + cache() + ->save($cacheName, $found, $secondsToNextUnpublishedPost ?: DECADE); + } + + return $found; + } + + /** + * Returns the timestamp difference in seconds between the next post to publish and the current timestamp. Returns + * false if there's no post to publish + */ + public function getSecondsToNextUnpublishedPosts(int $actorId): int | false + { + $result = $this->builder() + ->select('TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), `published_at`) as timestamp_diff') + ->where([ + 'actor_id' => $actorId, + ]) + ->where('`published_at` > UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'asc') + ->get() + ->getResultArray(); + + return $result !== [] + ? (int) $result[0]['timestamp_diff'] + : false; + } + + /** + * Retrieves all published replies for a given post. By default, it does not get replies from blocked actors. + * + * @return Post[] + */ + public function getPostReplies(string $postId, bool $withBlocked = false): array + { + $cacheName = + config('Fediverse') + ->cachePrefix . + "post#{$postId}_replies" . + ($withBlocked ? '_withBlocked' : ''); + + if (! ($found = cache($cacheName))) { + if (! $withBlocked) { + $this->select('fediverse_posts.*') + ->join('fediverse_actors', 'fediverse_actors.id = fediverse_posts.actor_id', 'inner') + ->where('fediverse_actors.is_blocked', 0); + } + + $this->where('in_reply_to_id', $this->uuid->fromString($postId) ->getBytes()) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'ASC'); + + // do not get private replies if public + if (! can_user_interact()) { + $this->where('is_private', false); + } + + $found = $this->findAll(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * Retrieves all published reblogs for a given post + * + * @return Post[] + */ + public function getPostReblogs(string $postId): array + { + $cacheName = + config('Fediverse') + ->cachePrefix . "post#{$postId}_reblogs"; + + if (! ($found = cache($cacheName))) { + $found = $this->where('reblog_of_id', $this->uuid->fromString($postId) ->getBytes()) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->orderBy('published_at', 'ASC') + ->findAll(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function addPreviewCard(string $postId, int $previewCardId): bool + { + return $this->db->table('fediverse_posts_preview_cards') + ->insert([ + 'post_id' => $this->uuid->fromString($postId) + ->getBytes(), + 'preview_card_id' => $previewCardId, + ]); + } + + /** + * Adds post in database along preview card if relevant + * + * @return string|false returns the new post id if success or false otherwise + */ + public function addPost( + Post $post, + bool $createPreviewCard = true, + bool $registerActivity = true, + ): bool|int|object|string { + helper('fediverse'); + + $this->db->transStart(); + + if (! ($newPostId = $this->insert($post, true))) { + $this->db->transRollback(); + + // Couldn't insert post + return false; + } + + if ($createPreviewCard) { + // parse message + $messageUrls = extract_urls_from_message($post->message); + + if ( + $messageUrls !== [] && + ($previewCard = get_or_create_preview_card_from_url(new URI($messageUrls[0]))) && + ! $this->addPreviewCard($newPostId, $previewCard->id) + ) { + $this->db->transRollback(); + // problem when linking post to preview card + return false; + } + } + + if ($post->in_reply_to_id === null) { + // post is not a reply + model('ActorModel', false) + ->builder() + ->where('id', $post->actor_id) + ->increment('posts_count'); + + Events::trigger('on_post_add', $post); + } + + if ($registerActivity) { + // set post id and uri to construct NoteObject + $post->id = $newPostId; + $post->uri = url_to('post', esc($post->actor->username), $newPostId); + + $createActivity = new CreateActivity(); + $noteObjectClass = config('Fediverse') + ->noteObject; + $createActivity + ->set('actor', $post->actor->uri) + ->set('object', new $noteObjectClass($post)); + + if ($post->in_reply_to_id !== null && $post->is_private) { + $createActivity->set('to', [$post->reply_to_post->actor->uri]); + } + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Create', + $post->actor_id, + $post->in_reply_to_id === null ? null : $post->reply_to_post->actor_id, + $newPostId, + $createActivity->toJSON(), + $post->published_at, + 'queued', + ); + + $createActivity->set('id', url_to('activity', esc($post->actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $createActivity->toJSON(), + ]); + } + + $this->clearCache($post); + + $this->db->transComplete(); + + return $newPostId; + } + + public function editPost(Post $updatedPost): bool + { + $this->db->transStart(); + + // update post create activity schedule in database + $scheduledActivity = model('ActivityModel', false) + ->where([ + 'type' => 'Create', + 'post_id' => $this->uuid + ->fromString($updatedPost->id) + ->getBytes(), + ]) + ->first(); + + // update published date in payload + $newPayload = $scheduledActivity->payload; + $newPayload->object->published = $updatedPost->published_at->format(DATE_W3C); + + model('ActivityModel', false) + ->update($scheduledActivity->id, [ + 'payload' => json_encode($newPayload, JSON_THROW_ON_ERROR), + 'scheduled_at' => $updatedPost->published_at, + ]); + + // update post + $updateResult = $this->update($updatedPost->id, $updatedPost); + + Events::trigger('on_post_edit', $updatedPost); + + $this->clearCache($updatedPost); + + $this->db->transComplete(); + + return $updateResult; + } + + /** + * Removes a post from the database and decrements meta data + */ + public function removePost(Post $post, bool $registerActivity = true): BaseResult | bool + { + $this->db->transStart(); + + // remove all post reblogs + foreach ($post->reblogs as $reblog) { + // FIXME: issue when actor is not local, can't get actor information + $this->undoReblog($reblog); + } + + // remove all replies + foreach ($post->replies as $reply) { + $this->removePost($reply); + } + + // check that preview card is no longer used elsewhere before deleting it + if ( + $post->preview_card && + $this->db + ->table('fediverse_posts_preview_cards') + ->where('preview_card_id', $post->preview_card->id) + ->countAll() <= 1 + ) { + model('PreviewCardModel', false)->deletePreviewCard($post->preview_card->id, $post->preview_card->url); + } + + if ($registerActivity) { + $deleteActivity = new DeleteActivity(); + $tombstoneObject = new TombstoneObject(); + $tombstoneObject->set('id', $post->uri); + $deleteActivity + ->set('actor', $post->actor->uri) + ->set('object', $tombstoneObject); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Delete', + $post->actor_id, + null, + null, + $deleteActivity->toJSON(), + Time::now(), + 'queued', + ); + + $deleteActivity->set('id', url_to('activity', esc($post->actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $deleteActivity->toJSON(), + ]); + } + + if ($post->in_reply_to_id === null && $post->reblog_of_id === null) { + model('ActorModel', false) + ->builder() + ->where('id', $post->actor_id) + ->decrement('posts_count'); + + Events::trigger('on_post_remove', $post); + } elseif ($post->in_reply_to_id !== null) { + if (! $post->is_private) { + // Post to remove is a reply + model('PostModel', false) + ->builder() + ->where('id', $this->uuid->fromString($post->in_reply_to_id) ->getBytes()) + ->decrement('replies_count'); + } + + Events::trigger('on_reply_remove', $post); + } + + $result = model('PostModel', false) + ->delete($post->id); + + $this->clearCache($post); + + $this->db->transComplete(); + + return $result; + } + + public function addReply( + Post $reply, + bool $createPreviewCard = true, + bool $registerActivity = true, + ): string | false { + if (! $reply->in_reply_to_id) { + throw new Exception('Passed post is not a reply!'); + } + + $this->db->transStart(); + + $postId = $this->addPost($reply, $createPreviewCard, $registerActivity); + + if (! $reply->is_private) { + model('PostModel', false) + ->builder() + ->where('id', $this->uuid->fromString($reply->in_reply_to_id) ->getBytes()) + ->increment('replies_count'); + } + + Events::trigger('on_post_reply', $reply); + + $this->clearCache($reply); + + $this->db->transComplete(); + + return $postId; + } + + public function reblog(Actor $actor, Post $post, bool $registerActivity = true): string | false + { + // cannot reblog a private post + if ($post->is_private) { + return false; + } + + $this->db->transStart(); + + $userId = null; + if (function_exists('user_id')) { + $userId = user_id(); + } + + $reblog = new Post([ + 'actor_id' => $actor->id, + 'reblog_of_id' => $post->id, + 'published_at' => Time::now(), + 'created_by' => $userId, + ]); + + // add reblog + $reblogId = $this->insert($reblog); + + model('ActorModel', false) + ->builder() + ->where('id', $actor->id) + ->increment('posts_count'); + + model('PostModel', false) + ->builder() + ->where('id', $this->uuid->fromString($post->id)->getBytes()) + ->increment('reblogs_count'); + + if ($registerActivity) { + $announceActivity = new AnnounceActivity($reblog); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Announce', + $actor->id, + $post->actor_id, + $post->id, + $announceActivity->toJSON(), + $reblog->published_at, + 'queued', + ); + + $announceActivity->set('id', url_to('activity', esc($post->actor->username), $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $announceActivity->toJSON(), + ]); + } + + Events::trigger('on_post_reblog', $actor, $post); + + $this->clearCache($post); + + $this->db->transComplete(); + + return $reblogId; + } + + public function undoReblog(Post $reblogPost, bool $registerActivity = true): BaseResult | bool + { + $this->db->transStart(); + + model('ActorModel', false) + ->builder() + ->where('id', $reblogPost->actor_id) + ->decrement('posts_count'); + + model('PostModel', false) + ->builder() + ->where('id', $this->uuid->fromString($reblogPost->reblog_of_id) ->getBytes()) + ->decrement('reblogs_count'); + + if ($registerActivity) { + $undoActivity = new UndoActivity(); + // get like activity + $activity = model('ActivityModel', false) + ->where([ + 'type' => 'Announce', + 'actor_id' => $reblogPost->actor_id, + 'post_id' => $this->uuid + ->fromString($reblogPost->reblog_of_id) + ->getBytes(), + ]) + ->first(); + + $announceActivity = new AnnounceActivity($reblogPost); + $announceActivity->set('id', url_to('activity', $reblogPost->actor->username, $activity->id)); + + $undoActivity + ->set('actor', $reblogPost->actor->uri) + ->set('object', $announceActivity); + + $activityId = model('ActivityModel', false) + ->newActivity( + 'Undo', + $reblogPost->actor_id, + $reblogPost->reblog_of_post->actor_id, + $reblogPost->reblog_of_id, + $undoActivity->toJSON(), + Time::now(), + 'queued', + ); + + $undoActivity->set('id', url_to('activity', $reblogPost->actor->username, $activityId)); + + model('ActivityModel', false) + ->update($activityId, [ + 'payload' => $undoActivity->toJSON(), + ]); + } + + Events::trigger('on_post_undo_reblog', $reblogPost); + + $result = model('PostModel', false) + ->delete($reblogPost->id); + + $this->clearCache($reblogPost); + + $this->db->transComplete(); + + return $result; + } + + public function toggleReblog(Actor $actor, Post $post): void + { + if ( + ! ($reblogPost = $this->where([ + 'actor_id' => $actor->id, + 'reblog_of_id' => $this->uuid + ->fromString($post->id) + ->getBytes(), + ])->first()) instanceof Post + ) { + $this->reblog($actor, $post); + } else { + $this->undoReblog($reblogPost); + } + } + + public function getTotalLocalPosts(): int + { + helper('fediverse'); + + $cacheName = config('Fediverse') + ->cachePrefix . 'blocked_actors'; + if (! ($found = cache($cacheName))) { + $result = $this->builder() + ->select('COUNT(*) as total_local_posts') + ->join('fediverse_actors', 'fediverse_actors.id = fediverse_posts.actor_id') + ->where('fediverse_actors.domain', get_current_domain()) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->get() + ->getResultArray(); + + $found = (int) $result[0]['total_local_posts']; + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function resetFavouritesCount(): int | false + { + $postsFavouritesCount = $this->db->table('fediverse_favourites') + ->select('post_id as id, COUNT(*) as `favourites_count`') + ->groupBy('id') + ->get() + ->getResultArray(); + + if ($postsFavouritesCount !== []) { + $this->uuidUseBytes = false; + return $this->updateBatch($postsFavouritesCount, 'id'); + } + + return 0; + } + + public function resetReblogsCount(): int | false + { + $postsReblogsCount = $this->builder() + ->select('fediverse_posts.id, COUNT(*) as `replies_count`') + ->join('fediverse_posts as p2', 'fediverse_posts.id = p2.reblog_of_id') + ->groupBy('fediverse_posts.id') + ->get() + ->getResultArray(); + + if ($postsReblogsCount !== []) { + $this->uuidUseBytes = false; + return $this->updateBatch($postsReblogsCount, 'id'); + } + + return 0; + } + + public function resetRepliesCount(): int | false + { + $postsRepliesCount = $this->builder() + ->select('fediverse_posts.id, COUNT(*) as `replies_count`') + ->join('fediverse_posts as p2', 'fediverse_posts.id = p2.in_reply_to_id') + ->groupBy('fediverse_posts.id') + ->get() + ->getResultArray(); + + if ($postsRepliesCount !== []) { + $this->uuidUseBytes = false; + return $this->updateBatch($postsRepliesCount, 'id'); + } + + return 0; + } + + public function clearCache(Post $post): void + { + $cachePrefix = config('Fediverse') + ->cachePrefix; + + $hashedPostUri = md5($post->uri); + + model('ActorModel', false) + ->clearCache($post->actor); + cache() + ->deleteMatching($cachePrefix . "post#{$post->id}*"); + cache() + ->deleteMatching($cachePrefix . "post-{$hashedPostUri}*"); + + if ($post->in_reply_to_id !== null) { + $this->clearCache($post->reply_to_post); + } + + if ($post->reblog_of_id !== null) { + $this->clearCache($post->reblog_of_post); + } + } + + /** + * @param array> $data + * @return array> + */ + protected function setPostId(array $data): array + { + $uuid4 = $this->uuid->{$this->uuidVersion}(); + $data['data']['id'] = $uuid4->toString(); + + if (! isset($data['data']['uri'])) { + $actor = model('ActorModel', false) + ->getActorById((int) $data['data']['actor_id']); + + $data['data']['uri'] = url_to('post', esc($actor->username), $uuid4->toString()); + } + + return $data; + } +} diff --git a/modules/Fediverse/Models/PreviewCardModel.php b/modules/Fediverse/Models/PreviewCardModel.php new file mode 100644 index 00000000..b0e64c96 --- /dev/null +++ b/modules/Fediverse/Models/PreviewCardModel.php @@ -0,0 +1,102 @@ + + */ + protected $allowedFields = [ + 'id', + 'url', + 'title', + 'description', + 'type', + 'author_name', + 'author_url', + 'provider_name', + 'provider_url', + 'image', + 'html', + ]; + + /** + * @var class-string + */ + protected $returnType = PreviewCard::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + public function getPreviewCardFromUrl(string $url): ?PreviewCard + { + $hashedPreviewCardUrl = md5($url); + $cacheName = + config('Fediverse') + ->cachePrefix . + "preview_card-{$hashedPreviewCardUrl}"; + if (! ($found = cache($cacheName))) { + $found = $this->where('url', $url) + ->first(); + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function getPostPreviewCard(string $postId): ?PreviewCard + { + $cacheName = + config('Fediverse') + ->cachePrefix . "post#{$postId}_preview_card"; + if (! ($found = cache($cacheName))) { + $found = $this->join( + 'fediverse_posts_preview_cards', + 'fediverse_posts_preview_cards.preview_card_id = id', + 'inner', + ) + ->where('post_id', service('uuid') ->fromString($postId) ->getBytes()) + ->first(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + public function deletePreviewCard(int $id, string $url): BaseResult | bool + { + $hashedPreviewCardUrl = md5($url); + cache() + ->delete(config('Fediverse') ->cachePrefix . "preview_card-{$hashedPreviewCardUrl}"); + + return $this->delete($id); + } +} diff --git a/app/Libraries/ActivityPub/Objects/ActorObject.php b/modules/Fediverse/Objects/ActorObject.php similarity index 75% rename from app/Libraries/ActivityPub/Objects/ActorObject.php rename to modules/Fediverse/Objects/ActorObject.php index b3280650..d00ccb84 100644 --- a/app/Libraries/ActivityPub/Objects/ActorObject.php +++ b/modules/Fediverse/Objects/ActorObject.php @@ -3,15 +3,15 @@ declare(strict_types=1); /** - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Objects; +namespace Modules\Fediverse\Objects; -use ActivityPub\Core\ObjectType; -use ActivityPub\Entities\Actor; +use Modules\Fediverse\Core\ObjectType; +use Modules\Fediverse\Entities\Actor; class ActorObject extends ObjectType { @@ -36,6 +36,8 @@ class ActorObject extends ObjectType protected string $url; + protected string $nodeInfo2Url; + /** * @var array */ @@ -59,27 +61,28 @@ class ActorObject extends ObjectType $this->preferredUsername = $actor->username; $this->summary = $actor->summary; $this->url = $actor->uri; + $this->nodeInfo2Url = url_to('nodeInfo2'); $this->inbox = $actor->inbox_url; $this->outbox = $actor->outbox_url; $this->followers = $actor->followers_url; $this->image = [ - 'type' => 'Image', + 'type' => 'Image', 'mediaType' => $actor->cover_image_mimetype, - 'url' => $actor->cover_image_url, + 'url' => $actor->cover_image_url, ]; $this->icon = [ - 'type' => 'Image', + 'type' => 'Image', 'mediaType' => $actor->avatar_image_mimetype, - 'url' => $actor->avatar_image_url, + 'url' => $actor->avatar_image_url, ]; if ($actor->public_key !== null) { $this->publicKey = [ - 'id' => $actor->public_key_id, - 'owner' => $actor->uri, + 'id' => $actor->public_key_id, + 'owner' => $actor->uri, 'publicKeyPem' => $actor->public_key, ]; } diff --git a/modules/Fediverse/Objects/NoteObject.php b/modules/Fediverse/Objects/NoteObject.php new file mode 100644 index 00000000..73af27a3 --- /dev/null +++ b/modules/Fediverse/Objects/NoteObject.php @@ -0,0 +1,57 @@ +id = $post->uri; + + $this->content = $post->message_html; + $this->published = $post->published_at->format(DATE_W3C); + $this->attributedTo = $post->actor->uri; + + if ($post->in_reply_to_id !== null) { + if ($post->is_private) { + $this->to = [$post->reply_to_post->actor->uri]; + } else { + $this->to[] = $post->reply_to_post->actor->uri; + } + + $this->inReplyTo = $post->reply_to_post->uri; + } + + $this->replies = url_to('post-replies', esc($post->actor->username), $post->id); + + if (! $post->is_private) { + $this->cc = [$post->actor->followers_url]; + } + } +} diff --git a/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php b/modules/Fediverse/Objects/OrderedCollectionObject.php similarity index 81% rename from app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php rename to modules/Fediverse/Objects/OrderedCollectionObject.php index 64e64c69..339ffb03 100644 --- a/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php +++ b/modules/Fediverse/Objects/OrderedCollectionObject.php @@ -5,15 +5,15 @@ declare(strict_types=1); /** * This class defines a Paginated OrderedCollection based on CodeIgniter4 Pager to get the pagination metadata * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Objects; +namespace Modules\Fediverse\Objects; -use ActivityPub\Core\ObjectType; use CodeIgniter\Pager\Pager; +use Modules\Fediverse\Core\ObjectType; class OrderedCollectionObject extends ObjectType { @@ -28,15 +28,15 @@ class OrderedCollectionObject extends ObjectType protected ?string $last = null; /** - * @param ObjectType[]|null $orderedItems + * @param ObjectType[]|list|null $orderedItems */ public function __construct( protected ?array $orderedItems = null, - ?Pager $pager = null + ?Pager $pager = null, ) { $this->id = current_url(); - if ($pager !== null) { + if ($pager instanceof Pager) { $totalItems = $pager->getTotal(); $this->totalItems = $totalItems; diff --git a/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php b/modules/Fediverse/Objects/OrderedCollectionPage.php similarity index 94% rename from app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php rename to modules/Fediverse/Objects/OrderedCollectionPage.php index de177ebd..afa6835c 100644 --- a/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php +++ b/modules/Fediverse/Objects/OrderedCollectionPage.php @@ -5,12 +5,12 @@ declare(strict_types=1); /** * This class defines a Paginated OrderedCollection based on CodeIgniter4 Pager to get the pagination metadata * - * @copyright 2021 Podlibre + * @copyright 2021 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ -namespace ActivityPub\Objects; +namespace Modules\Fediverse\Objects; use CodeIgniter\Pager\Pager; @@ -33,6 +33,7 @@ class OrderedCollectionPage extends OrderedCollectionObject if ($isFirstPage) { $this->first = null; } + if ($isLastPage) { $this->last = null; } diff --git a/modules/Fediverse/Objects/TombstoneObject.php b/modules/Fediverse/Objects/TombstoneObject.php new file mode 100644 index 00000000..f86b9c97 --- /dev/null +++ b/modules/Fediverse/Objects/TombstoneObject.php @@ -0,0 +1,18 @@ +([\w_]+))@(?P([\w\-\.]+[\w]+)(:[\d]+)?)$/x'; + + protected string $username; + + protected string $domain; + + protected string $host; + + protected string $port; + + /** + * @var string[] + */ + protected array $aliases = []; + + /** + * @var array> + */ + protected array $links = []; + + public function __construct( + protected string $subject, + ) { + // Split resource into its parts (username, domain) + $parts = $this->splitResource($subject); + if (! $parts) { + throw new Exception('Wrong WebFinger resource pattern.'); + } + + $username = $parts['username']; + $domain = $parts['domain']; + + $this->username = $username; + $this->domain = $domain; + + $currentUrl = current_url(true); + $currentDomain = + $currentUrl->getHost() . + ($currentUrl->getPort() ? ':' . $currentUrl->getPort() : ''); + if ($currentDomain !== $domain) { + // TODO: return error code + throw new Exception('Domain does not correspond to Instance.'); + } + + if ( + ! ($actor = model('ActorModel', false)->getActorByUsername($username, $domain)) instanceof Actor + ) { + throw new Exception('Could not find actor'); + } + + $this->aliases = [$actor->uri]; + $this->links = [ + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => $actor->uri, + ], + [ + 'rel' => 'http://webfinger.net/rel/profile-page', + 'type' => 'text/html', + 'href' => $actor->uri, + # TODO: should there be 2 values? @actorUsername + ], + ]; + } + + /** + * Get WebFinger response as an array + * + * @return array{subject: string, aliases: string[], links: array>} + */ + public function toArray(): array + { + return [ + 'subject' => $this->subject, + 'aliases' => $this->aliases, + 'links' => $this->links, + ]; + } + + /** + * Split resource into its parts (username, domain) + * + * @return array{0:string,username:non-empty-string,1:non-empty-string,2:non-empty-string,domain:non-falsy-string,3:non-falsy-string,4:non-falsy-string,5?:non-falsy-string} + */ + private function splitResource(string $resource): bool|array + { + if (! preg_match(self::RESOURCE_PATTERN, $resource, $matches)) { + // Resource pattern failed + return false; + } + + return $matches; + } +} diff --git a/modules/Install/Commands/CreateSuperadmin.php b/modules/Install/Commands/CreateSuperadmin.php new file mode 100644 index 00000000..0dfdad71 --- /dev/null +++ b/modules/Install/Commands/CreateSuperadmin.php @@ -0,0 +1,145 @@ +> + */ + private array $validationRules = []; + + #[Override] + public function run(array $params): void + { + // first, check that super admin does not exist + $userModel = model('UserModel'); + $isSuperAdminCreated = $userModel->where('is_owner', true) + ->countAllResults(); + + if ($isSuperAdminCreated > 0) { + $this->write('Super admin was already created!', 'red'); + + exit(EXIT_ERROR); + } + + $this->setValidationRules(); + + $username = $params['n'] ?? null; + $email = $params['e'] ?? null; + + $data = [ + 'is_owner' => true, + ]; + + if ($username === null) { + $username = $this->prompt('Username', null, $this->validationRules['username']['rules']); + } + + $data['username'] = $username; + + if ($email === null) { + $email = $this->prompt('Email', null, $this->validationRules['email']['rules']); + } + + $data['email'] = $email; + + $password = $this->prompt('Password', null, $this->validationRules['password']['rules']); + $passwordConfirm = $this->prompt( + 'Password confirmation', + null, + $this->validationRules['password']['rules'], + ); + + if ($password !== $passwordConfirm) { + throw new BadInputException("The passwords don't match"); + } + + $data['password'] = $password; + + // Run validation if the user has passed username and/or email via command line + $validation = service('validation'); + $validation->setRules($this->validationRules); + + if (! $validation->run($data)) { + foreach ($validation->getErrors() as $message) { + $this->write($message, 'red'); + } + + throw new CancelException('Super admin creation aborted'); + } + + $userModel = model('UserModel'); + + $user = new User($data); + $userModel->save($user); + + $user = $userModel->findById($userModel->getInsertID()); + + // set newly created user as most powerful instance group (superadmin) + $user->addGroup(setting('AuthGroups.mostPowerfulGroup')); + + $this->write('Super admin "' . $username . '" created', 'green'); + } + + private function setValidationRules(): void + { + $validationRules = new ValidationRules(); + + $rules = $validationRules->getRegistrationRules(); + + // Remove `strong_password` because it only supports use cases + // to check the user's own password. + $passwordRules = $rules['password']['rules']; + if (is_string($passwordRules)) { + $passwordRules = explode('|', $passwordRules); + } + + if (($key = array_search('strong_password[]', $passwordRules, true)) !== false) { + unset($passwordRules[$key]); + } + + if (($key = array_search('strong_password', $passwordRules, true)) !== false) { + unset($passwordRules[$key]); + } + + $config = config('Auth'); + + // Add `min_length` + $passwordRules[] = 'min_length[' . $config->minimumPasswordLength . ']'; + + $rules['password']['rules'] = $passwordRules; + + $this->validationRules = [ + 'username' => $rules['username'], + 'email' => $rules['email'], + 'password' => $rules['password'], + ]; + } +} diff --git a/modules/Install/Commands/InitDatabase.php b/modules/Install/Commands/InitDatabase.php new file mode 100644 index 00000000..67d8f61b --- /dev/null +++ b/modules/Install/Commands/InitDatabase.php @@ -0,0 +1,40 @@ +setNamespace(null) + ->latest(); + + // Seed database + $seeder = Database::seeder(); + $seeder->call('AppSeeder'); + } +} diff --git a/modules/Install/Config/Install.php b/modules/Install/Config/Install.php new file mode 100644 index 00000000..db5b2030 --- /dev/null +++ b/modules/Install/Config/Install.php @@ -0,0 +1,18 @@ +group( + config('Install') + ->gateway, + [ + 'namespace' => 'Modules\Install\Controllers', + ], + static function ($routes): void { + $routes->get('/', 'InstallController', [ + 'as' => 'install', + ]); + $routes->post('instance-config', 'InstallController::instanceConfigAction', [ + 'as' => 'instance-config', + ]); + $routes->post('database-config', 'InstallController::databaseConfigAction', [ + 'as' => 'database-config', + ]); + $routes->post('cache-config', 'InstallController::cacheConfigAction', [ + 'as' => 'cache-config', + ]); + $routes->post( + 'create-superadmin', + 'InstallController::createSuperAdminAction', + [ + 'as' => 'create-superadmin', + ], + ); + }, +); diff --git a/modules/Install/Controllers/InstallController.php b/modules/Install/Controllers/InstallController.php new file mode 100644 index 00000000..f6f875af --- /dev/null +++ b/modules/Install/Controllers/InstallController.php @@ -0,0 +1,360 @@ + + */ + protected $helpers = ['form', 'components', 'svg', 'misc', 'setting']; + + #[Override] + public function initController( + RequestInterface $request, + ResponseInterface $response, + LoggerInterface $logger, + ): void { + // Do Not Edit This Line + parent::initController($request, $response, $logger); + + Theme::setTheme('install'); + } + + /** + * Every operation goes through this method to handle the install logic. + * + * If all required actions have already been performed, the install route will show a 404 page. + */ + public function index(): string + { + if (! file_exists(ROOTPATH . '.env')) { + // create empty .env file + try { + $envFile = fopen(ROOTPATH . '.env', 'w'); + fclose($envFile); + } catch (Throwable) { + // Could not create the .env file, redirect to a view with instructions on how to add it manually + return view('manual_config'); + } + } + + // Check if .env has all required fields + $dotenv = Dotenv::createUnsafeImmutable(ROOTPATH); + $dotenv->load(); + + // Check if the created .env file is writable to continue install process + if (is_really_writable(ROOTPATH . '.env')) { + try { + $dotenv->required(['app.baseURL', 'analytics.salt', 'admin.gateway', 'auth.gateway']); + } catch (ValidationException) { + // form to input instance configuration + return $this->instanceConfigView(); + } + + try { + $dotenv->required([ + 'database.default.hostname', + 'database.default.database', + 'database.default.username', + 'database.default.password', + 'database.default.DBPrefix', + ]); + } catch (ValidationException) { + return $this->databaseConfigView(); + } + + try { + $dotenv->required('cache.handler'); + } catch (ValidationException) { + return $this->cacheConfigView(); + } + } else { + try { + $dotenv->required([ + 'app.baseURL', + 'analytics.salt', + 'admin.gateway', + 'auth.gateway', + 'database.default.hostname', + 'database.default.database', + 'database.default.username', + 'database.default.password', + 'database.default.DBPrefix', + 'cache.handler', + ]); + } catch (ValidationException) { + return view('manual_config'); + } + } + + try { + $db = db_connect(); + + // Check if instance owner has been created, meaning install was completed + if ($db->tableExists('users') && new UserModel()->where('is_owner', true) + ->first() instanceof User + ) { + // if so, show a 404 page + throw PageNotFoundException::forPageNotFound(); + } + } catch (DatabaseException) { + // Could not connect to the database + // show database config view to fix value + session() + ->setFlashdata('error', lang('Install.messages.databaseConnectError')); + + return $this->databaseConfigView(); + } + + // migrate if no user has been created + $this->migrate(); + + // Check if all seeds have succeeded + $this->seed(); + + return $this->createSuperAdminView(); + } + + public function instanceConfigView(): string + { + return view('instance_config'); + } + + public function instanceConfigAction(): RedirectResponse + { + $rules = [ + 'hostname' => 'required|valid_url_strict', + 'media_base_url' => 'permit_empty|valid_url_strict', + 'admin_gateway' => 'required', + 'auth_gateway' => 'required|differs[admin_gateway]', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->to((host_url() ?? config('App') ->baseURL) . config('Install')->gateway) + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $baseUrl = $validData['hostname']; + $mediaBaseUrl = $validData['media_base_url']; + self::writeEnv([ + 'app.baseURL' => $baseUrl, + 'media.baseURL' => $mediaBaseUrl === '' ? $baseUrl : $mediaBaseUrl, + 'analytics.salt' => generate_random_salt(64), + 'admin.gateway' => $validData['admin_gateway'], + 'auth.gateway' => $validData['auth_gateway'], + ]); + + helper('text'); + + // redirect to full install url with new baseUrl input + return redirect()->to(reduce_double_slashes($baseUrl . '/' . config('Install')->gateway)); + } + + public function databaseConfigView(): string + { + return view('database_config'); + } + + public function databaseConfigAction(): RedirectResponse + { + $rules = [ + 'db_hostname' => 'required', + 'db_name' => 'required', + 'db_username' => 'required', + 'db_password' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + self::writeEnv([ + 'database.default.hostname' => $validData['db_hostname'], + 'database.default.database' => $validData['db_name'], + 'database.default.username' => $validData['db_username'], + 'database.default.password' => $validData['db_password'], + 'database.default.DBPrefix' => $this->request->getPost('db_prefix'), + ]); + + return redirect()->back(); + } + + public function cacheConfigView(): string + { + return view('cache_config'); + } + + public function cacheConfigAction(): RedirectResponse + { + $rules = [ + 'cache_handler' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + self::writeEnv([ + 'cache.handler' => $validData['cache_handler'], + ]); + + return redirect()->back(); + } + + /** + * Runs all database migrations required for instance. + */ + public function migrate(): void + { + $migrate = service('migrations'); + + $migrate->setNamespace(null) + ->latest(); + } + + /** + * Runs all database seeds required for instance. + */ + public function seed(): void + { + $seeder = Database::seeder(); + + // Seed database + $seeder->call('AppSeeder'); + } + + /** + * Returns the form to create a the first superadmin user for the instance. + */ + public function createSuperAdminView(): string + { + return view('create_superadmin'); + } + + /** + * Creates the first superadmin user or redirects back to form if any error. + * + * After creation, user is redirected to login page to input its credentials. + */ + public function createSuperAdminAction(): RedirectResponse + { + // validate user password + $rules = [ + 'username' => 'required', + 'email' => 'required', + 'password' => 'required|strong_password', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + // Save the user + $user = new User([ + 'username' => $validData['username'], + 'email' => $validData['email'], + 'password' => $validData['password'], + 'is_owner' => true, + ]); + + $userModel = new UserModel(); + try { + $userModel->save($user); + } catch (ShieldValidationException) { + return redirect()->back() + ->withInput() + ->with('errors', $userModel->errors()); + } + + $user = $userModel->findById($userModel->getInsertID()); + + // set newly created user as most powerful instance group (superadmin) + $user->addGroup(setting('AuthGroups.mostPowerfulGroup')); + + // Success! + // set redirect_url session as admin area to go to after login + session() + ->set('redirect_url', route_to('admin')); + + return redirect() + ->route('admin') + ->with('message', lang('Install.messages.createSuperAdminSuccess')); + } + + /** + * writes config values in .env file overwrites any existing key and appends new ones + * + * @param array $configData key/value config pairs + */ + public static function writeEnv(array $configData): void + { + $envData = file(ROOTPATH . '.env'); // reads an array of lines + + foreach ($configData as $key => $value) { + $replaced = false; + $keyVal = $key . '="' . $value . '"' . PHP_EOL; + $envData = array_map( + static function ($line) use ($key, $keyVal, &$replaced) { + if (str_starts_with($line, $key)) { + $replaced = true; + return $keyVal; + } + + return $line; + }, + $envData, + ); + + if (! $replaced) { + $envData[] = $keyVal; + } + } + + file_put_contents(ROOTPATH . '.env', implode('', $envData)); + } +} diff --git a/modules/Install/Language/.gitkeep b/modules/Install/Language/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/modules/Install/Language/.rsync-filter b/modules/Install/Language/.rsync-filter new file mode 100644 index 00000000..b802a93d --- /dev/null +++ b/modules/Install/Language/.rsync-filter @@ -0,0 +1,12 @@ ++ en/*** ++ fr/*** ++ pl/*** ++ de/*** ++ pt-br/*** ++ nn-no/*** ++ es/*** ++ zh-hans/*** ++ ca/*** ++ br/*** ++ sr-latn/*** +- ** diff --git a/modules/Install/Language/ar/Install.php b/modules/Install/Language/ar/Install.php new file mode 100644 index 00000000..784f30d8 --- /dev/null +++ b/modules/Install/Language/ar/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'اسم المضيف', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'اسم مضيف قاعدة البيانات', + 'db_name' => 'اسم قاعدة البيانات', + 'db_username' => 'اسم المستخدم لقاعدة البيانات', + 'db_password' => 'كلمة مرور قاعدة البيانات', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'ملف', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'إنهاء التثبيت', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'البريد الإلكتروني', + 'username' => 'اسم المستخدم', + 'password' => 'كلمة المرور', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/br/Install.php b/modules/Install/Language/br/Install.php new file mode 100644 index 00000000..c29b77e2 --- /dev/null +++ b/modules/Install/Language/br/Install.php @@ -0,0 +1,62 @@ + 'Stalier Castopod', + 'manual_config' => 'Kefluniañ dre zorn', + 'manual_config_subtitle' => + 'Krouit ur restr `.env` gant hoc’h arventennoù ha nevesait ar bajenn evit kenderc\'hel gant ar staliañ.', + 'form' => [ + 'instance_config' => 'Arventennoù an istañs', + 'hostname' => 'Anv an ostiz', + 'media_base_url' => 'Chomlec\'h diazez ar mediaoù', + 'media_base_url_hint' => + 'Ma \'z implijit ur CDN pe ur servij diavaez evit muzuliañ heklev, e c\'hellit lakaat anezho amañ.', + 'admin_gateway' => 'Chomlec\'h an daolenn-stur', + 'admin_gateway_hint' => + 'An hent evit mont d\'an daolenn-stur (da sk. https://skouer.bzh/cp-admin). Dre ziouer eo cp-admin, met erbedet oc\'h kemmañ anezhañ evit abegoù a denn d\'an diogelroez.', + 'auth_gateway' => 'Chomlec\'h ar c\'hennaskañ', + 'auth_gateway_hint' => + 'An hent evit mont d\'ar bajenn gennaskañ (da sk. https://skouer.bzh/cp-auth). Dre ziouer eo cp-auth, met erbedet oc\'h kemmañ anezhañ evit abegoù a denn d\'an diogelroez.', + 'database_config' => 'Arventennoù ar stlennvon', + 'database_config_hint' => + 'Castopod a rank bezañ kennesket ouzh ho stlennvon MySQL (pe MariaDB). Mont e darempred gant merour ho tafariad ma n\'emañ ket ganeoc\'h an titouroù-se.', + 'db_hostname' => 'Anv ostiz ar stlennvon', + 'db_name' => 'Anv ar stlennvon (an diaz)', + 'db_username' => 'Anv implijer ar stlennvon', + 'db_password' => 'Ger-tremen ar stlennvon', + 'db_prefix' => 'Rakger an taolennoù', + 'db_prefix_hint' => + "Rakger taolennoù Castopod. Laoskit evel m'emañ ma ne ouzoc'h ket petra a dalv.", + 'cache_config' => 'Arventennoù ar grubuilh (cache)', + 'cache_config_hint' => + 'Dibabit hoc’h ardoer krubuilh muiañ plijet. Laoskit evel m\'emañ ma ne ouzoc\'h ket petra a dalv.', + 'cache_handler' => 'Aorder krubuilh', + 'cacheHandlerOptions' => [ + 'file' => 'Restroù', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'War-lerc\'h', + 'submit' => 'Echuiñ ar staliañ', + 'create_superadmin' => 'Krouit ho kont gourverour·ez (superadmin)', + 'email' => 'Postel', + 'username' => 'Anv implijer·ez', + 'password' => 'Ger-tremen', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ho kont gourverour·ez a zo bet krouet gant berzh. Kevreit ha krogit da bodkastiñ!', + 'databaseConnectError' => + 'N\'en deus ket gellet Castopod kevreañ ouzh ho stlennvon. Kemmit arventennoù ar stlennvon ha klaskit en-dro.', + 'writeError' => + "N'haller ket krouiñ/skrivañ ar restr `.env`. Deoc'h-c'hwi da grouiñ anezhi dre zorn diwar ar patrom `.env.example` az o e pakad Castopod.", + ], +]; diff --git a/modules/Install/Language/ca/Install.php b/modules/Install/Language/ca/Install.php new file mode 100644 index 00000000..640fadab --- /dev/null +++ b/modules/Install/Language/ca/Install.php @@ -0,0 +1,62 @@ + 'Instal·lador de Castopod', + 'manual_config' => 'Configuració manual', + 'manual_config_subtitle' => + 'Creeu un fitxer `.env` amb la vostra configuració i actualitzeu la pàgina per continuar amb la instal·lació.', + 'form' => [ + 'instance_config' => 'Configuració de la instància', + 'hostname' => 'Nom del servidor (hostname)', + 'media_base_url' => 'URL de base pel multimèdia', + 'media_base_url_hint' => + 'Si utilitzeu un CDN i/o un servei d\'anàlisi de tràfic extern, podeu configurar-los aquí.', + 'admin_gateway' => 'Porta d\'enllaç al panell admin', + 'admin_gateway_hint' => + 'La ruta per accedir a l\'àrea d\'administració (p. ex., https://exemple.com/cp-admin). Està configurat per defecte com a cp-admin, us recomanem que el canvieu per motius de seguretat.', + 'auth_gateway' => 'Porta d\'enllaç per l\'autenticació', + 'auth_gateway_hint' => + 'La ruta per accedir a les pàgines d\'autenticació (p. ex. https://exemple.com/cp-auth). Està configurada per defecte com a cp-auth, us recomanem que el canvieu per motius de seguretat.', + 'database_config' => 'Configuració de la Base de Dades', + 'database_config_hint' => + 'Castopod s\'ha de connectar a la vostra base de dades MySQL (o MariaDB). Si no teniu aquesta informació necessària, poseu-vos en contacte amb l\'administrador del vostre servidor.', + 'db_hostname' => 'Nom del servidor (host) de la base de dades', + 'db_name' => 'Nom de la base de dades', + 'db_username' => 'Usuari de la base de dades', + 'db_password' => 'Contrasenya de la base de dades', + 'db_prefix' => 'Prefix de la base de dades', + 'db_prefix_hint' => + "El prefix emprat als noms de les taules de Castopod, deixeu-lo com està si no sabeu què significa.", + 'cache_config' => 'Configuració de la memòria cau', + 'cache_config_hint' => + 'Trieu el vostre gestor de memòria cau preferit. Deixeu-lo com a valor predeterminat si no teniu ni idea del que significa.', + 'cache_handler' => 'Gestor de memòria cau', + 'cacheHandlerOptions' => [ + 'file' => 'Fitxer', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Següent', + 'submit' => 'Finalitzar la instal·lació', + 'create_superadmin' => 'Crear el vostre compte de super-usuari', + 'email' => 'Correu electrònic', + 'username' => 'Nom de l\'usuari', + 'password' => 'Contrasenya', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'El vostre compte de superadministrador s\'ha creat correctament. Inicieu sessió per començar a fer podcasts!', + 'databaseConnectError' => + 'Castopod no s\'ha pogut connectar a la vostra base de dades. Editeu la configuració de la vostra base de dades i torneu-ho a provar.', + 'writeError' => + "No s'ha pogut crear/escriure el fitxer `.env`. Heu de crear-lo manualment seguint la plantilla de fitxer `.env.example` del paquet Castopod.", + ], +]; diff --git a/modules/Install/Language/da/Install.php b/modules/Install/Language/da/Install.php new file mode 100644 index 00000000..16bbbd54 --- /dev/null +++ b/modules/Install/Language/da/Install.php @@ -0,0 +1,62 @@ + 'Castopod installationsprogram', + 'manual_config' => 'Manuel konfiguration', + 'manual_config_subtitle' => + 'Opret en `.env` fil med dine indstillinger og opdater siden for at fortsætte installationen.', + 'form' => [ + 'instance_config' => 'Instanskonfiguration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Medie base URL', + 'media_base_url_hint' => + 'Hvis du bruger en CDN og/eller en ekstern analysetjeneste, kan du indstille dem her.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod skal oprette forbindelse til din MySQL (eller MariaDB) database. Hvis du ikke har disse nødvendige oplysninger, bedes du kontakte din serveradministrator.', + 'db_hostname' => 'Database host navn', + 'db_name' => 'Databasenavn', + 'db_username' => 'Database brugernavn', + 'db_password' => 'Database adgangskode', + 'db_prefix' => 'Database præfiks', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Næste', + 'submit' => 'Afslut installation', + 'create_superadmin' => 'Opret din Super Admin konto', + 'email' => 'Email', + 'username' => 'Brugernavn', + 'password' => 'Adgangskode', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Din superadmin konto er blevet oprettet. Log ind for at starte podcasting!', + 'databaseConnectError' => + 'Castopod kunne ikke oprette forbindelse til din database. Rediger din database konfiguration og prøv igen.', + 'writeError' => + "Kunne ikke oprette/skrive `.env` filen. Du skal oprette den manuelt ved at følge `.env.example` filskabelon i Castopod-pakken.", + ], +]; diff --git a/modules/Install/Language/de/Install.php b/modules/Install/Language/de/Install.php new file mode 100644 index 00000000..ecebbfa7 --- /dev/null +++ b/modules/Install/Language/de/Install.php @@ -0,0 +1,62 @@ + 'Castopod-Installer', + 'manual_config' => 'Manuelle Konfiguration', + 'manual_config_subtitle' => + 'Erstelle eine `.env`-Datei mit deinen Einstellungen und aktualisiere die Seite, um die Installation fortzusetzen.', + 'form' => [ + 'instance_config' => 'Instance-Konfiguration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Medien-Basis-URL', + 'media_base_url_hint' => + 'Wenn du einen CDN und/oder einen externen Analysedienst verwendest, kannst du diesen hier festlegen.', + 'admin_gateway' => 'Admin-Gateway', + 'admin_gateway_hint' => + 'Der Pfad zum Zugriff auf den Admin-Bereich (z.B. https://example.com/cp-admin), wird standardmäßig als "cp-admin" festgelegt. Wir empfehlen, sie aus Sicherheitsgründen zu ändern.', + 'auth_gateway' => 'Auth-Gateway', + 'auth_gateway_hint' => + 'Der Pfad zum Zugriff auf die Authentifizierungsseiten (z. B. https://example.com/cp-auth), wird standardmäßig als "cp-auth" gesetzt. Wir empfehlen, sie aus Sicherheitsgründen zu ändern.', + 'database_config' => 'Datenbankkonfiguration', + 'database_config_hint' => + 'Castopod muss sich mit der MySQL-Datenbank (oder MariaDB) verbinden. Wenn diese erforderlichen Informationen nicht verfügbar sind, wende dich bitte an deinen Serveradministrator.', + 'db_hostname' => 'Datenbank Hostname', + 'db_name' => 'Datenbankname', + 'db_username' => 'Datenbank-Benutzername', + 'db_password' => 'Datenbank-Passwort', + 'db_prefix' => 'Datenbankpräfix', + 'db_prefix_hint' => + "Das Präfix der Castopod-Tabellennamen. Nicht anpassen, wenn nicht klar ist was damit gemeint ist.", + 'cache_config' => 'Cache-Konfiguration', + 'cache_config_hint' => + 'Wähle deinen bevorzugten Cache-Handler. Belasse den Standardwert, wenn du keine Ahnung hast, was er bedeutet.', + 'cache_handler' => 'Cache-Handler', + 'cacheHandlerOptions' => [ + 'file' => 'Datei', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Weiter', + 'submit' => 'Installation abschließen', + 'create_superadmin' => 'Erstelle deinen Superadmin-Account', + 'email' => 'E-Mail', + 'username' => 'Benutzername', + 'password' => 'Passwort', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Dein Superadmin-Account wurde erfolgreich erstellt. Melde dich an, um mit dem Podcasting zu starten!', + 'databaseConnectError' => + 'Castopod konnte keine Verbindung zur Datenbank herstellen. Bearbeite die Datenbankkonfiguration und versuche es erneut.', + 'writeError' => + "Konnte die `.env`-Datei nicht erstellen/schreiben. Du musst sie manuell erstellen, indem du dem `.env.example` Template im Castopod Paket folgst.", + ], +]; diff --git a/modules/Install/Language/el/Install.php b/modules/Install/Language/el/Install.php new file mode 100644 index 00000000..c8edb139 --- /dev/null +++ b/modules/Install/Language/el/Install.php @@ -0,0 +1,62 @@ + 'Εγκαταστάτης Castopod', + 'manual_config' => 'Χειροκίνητη ρύθμιση', + 'manual_config_subtitle' => + 'Δημιουργήστε ένα αρχείο `.env` με τις ρυθμίσεις σας και ανανεώστε τη σελίδα για να συνεχίσετε την εγκατάσταση.', + 'form' => [ + 'instance_config' => 'Ρύθμιση παραμέτρων εμφάνισης', + 'hostname' => 'Όνομα κεντρικού υπολογιστή', + 'media_base_url' => 'Διεύθυνση URL πολυμέσων', + 'media_base_url_hint' => + 'Εάν χρησιμοποιείτε μια υπηρεσία CDN και/ ή μια εξωτερική υπηρεσία ανάλυσης, μπορείτε να την ρυθμίσετε εδώ.', + 'admin_gateway' => 'Πύλη διαχειριστή', + 'admin_gateway_hint' => + 'Η διαδρομή πρόσβασης στην περιοχή διαχειριστή (π.χ. https://example.com/cp-admin). Έχει οριστεί από προεπιλογή ως cp-admin, σας συνιστούμε να την αλλάξετε για λόγους ασφαλείας.', + 'auth_gateway' => 'Πύλη ταυτοποίησης', + 'auth_gateway_hint' => + 'Η διαδρομή πρόσβασης στην περιοχή διαχειριστή (π.χ. https://example.com/cp-auth). Έχει οριστεί από προεπιλογή ως cp-admin, σας συνιστούμε να την αλλάξετε για λόγους ασφαλείας.', + 'database_config' => 'Ρυθμίσεις βάσης δεδομένων', + 'database_config_hint' => + 'Το Castopod πρέπει να συνδεθεί στη βάση δεδομένων MySQL (ή MariaDB). Αν δεν έχετε αυτές τις απαιτούμενες πληροφορίες, παρακαλούμε επικοινωνήστε με το διαχειριστή του διακομιστή σας.', + 'db_hostname' => 'Όνομα κεντρικού υπολογιστή βάσης δεδομένων', + 'db_name' => 'Όνομα βάσης δεδομένων', + 'db_username' => 'Όνομα Χρήστη Βάσης Δεδομένων', + 'db_password' => 'Κωδικός πρόσβασης βάσης δεδομένων', + 'db_prefix' => 'Πρόθεμα βάσης δεδομένων', + 'db_prefix_hint' => + "Το πρόθεμα των ονομασιών πινάκων Castopod αφήστε σαν να μην ξέρετε τι σημαίνει.", + 'cache_config' => 'Διαμόρφωση cache', + 'cache_config_hint' => + 'Επιλέξτε τον προτιμώμενο χειριστή προσωρινής μνήμης. Αφήστε την προεπιλεγμένη τιμή αν δεν έχετε ιδέα τι σημαίνει.', + 'cache_handler' => 'Ρυθμιστής cache', + 'cacheHandlerOptions' => [ + 'file' => 'Αρχείο', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Επόμενο', + 'submit' => 'Ολοκλήρωση εγκατάστασης', + 'create_superadmin' => 'Δημιουργήστε το λογαριασμό υπερδιαχειριστή', + 'email' => 'Email', + 'username' => 'Όνομα Χρήστη', + 'password' => 'Κωδικόs πρόσβασης', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ο λογαριασμός υπερδιαχειριστή έχει δημιουργηθεί με επιτυχία. Συνδεθείτε για να ξεκινήσετε το podcasting!', + 'databaseConnectError' => + 'Το Castopod δεν μπόρεσε να συνδεθεί στη βάση δεδομένων σας. Επεξεργαστείτε τη διαμόρφωση της βάσης δεδομένων σας και προσπαθήστε ξανά.', + 'writeError' => + "Δεν ήταν δυνατή η δημιουργία/εγγραφή του αρχείου `.env`. Πρέπει να το δημιουργήσετε χειροκίνητα ακολουθώντας το πρότυπο αρχείου `.env.example` που περιγράφεται στο Castopod.", + ], +]; diff --git a/modules/Install/Language/en/Install.php b/modules/Install/Language/en/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/en/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/es/Install.php b/modules/Install/Language/es/Install.php new file mode 100644 index 00000000..fa066b11 --- /dev/null +++ b/modules/Install/Language/es/Install.php @@ -0,0 +1,62 @@ + 'Instalador de Castopod', + 'manual_config' => 'Configuración manual', + 'manual_config_subtitle' => + 'Crea un archivo `.env` con tus ajustes y actualiza la página para continuar la instalación.', + 'form' => [ + 'instance_config' => 'Configuración de Instancia', + 'hostname' => 'Nombre de host', + 'media_base_url' => 'URL del reproductor de medios', + 'media_base_url_hint' => + 'Si utiliza un CDN y/o un servicio de análisis externo, puede establecerlo aquí.', + 'admin_gateway' => 'Pasarela de administración', + 'admin_gateway_hint' => + 'La ruta para acceder al área de administración (por ejemplo, https://example.com/cp-admin). Se establece por defecto como cp-admin, le recomendamos que lo cambie por razones de seguridad.', + 'auth_gateway' => 'Pasarela de autenticación', + 'auth_gateway_hint' => + 'La ruta para acceder al área de administración (por ejemplo, https://example.com/cp-auth). Se establece por defecto como cp-admin, le recomendamos que lo cambie por razones de seguridad.', + 'database_config' => 'Configuración de la base de datos', + 'database_config_hint' => + 'Castopod necesita conectarse a su base de datos MySQL (o MariaDB). Si no tiene esta información requerida, póngase en contacto con el administrador de su servidor.', + 'db_hostname' => 'Nombre del servidor de la Base de Datos', + 'db_name' => 'Nombre de la base de datos', + 'db_username' => 'Nombre de usuario de la base de datos', + 'db_password' => 'Contraseña de la base de datos', + 'db_prefix' => 'Prefijo de la base de datos', + 'db_prefix_hint' => + "El prefijo de los nombres de la tabla de Castopod, déjalo como si no sabes lo que significa.", + 'cache_config' => 'Configuración del caché', + 'cache_config_hint' => + 'Elija su gestor de caché preferido. Déjelo como el valor predeterminado si no tiene ni idea de lo que significa.', + 'cache_handler' => 'Manejador de cache', + 'cacheHandlerOptions' => [ + 'file' => 'Archivo', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Siguiente', + 'submit' => 'Finalizar la instalación', + 'create_superadmin' => 'Crear la cuenta de administración', + 'email' => 'Correo electrónico', + 'username' => 'Nombre de usuario', + 'password' => 'Contraseña', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Tu cuenta de superadmin se ha creado correctamente. ¡Inicia sesión para empezar a podcasting!', + 'databaseConnectError' => + 'Castopod no pudo conectarse a su base de datos. Edite la configuración de la base de datos y vuelva a intentarlo.', + 'writeError' => + "No se pudo crear/escribir el archivo `.env`. Debes crearlo manualmente siguiendo la plantilla de archivo `.env.example` en el paquete Castopod.", + ], +]; diff --git a/modules/Install/Language/eu/Install.php b/modules/Install/Language/eu/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/eu/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/fa/Install.php b/modules/Install/Language/fa/Install.php new file mode 100644 index 00000000..0164c3f8 --- /dev/null +++ b/modules/Install/Language/fa/Install.php @@ -0,0 +1,62 @@ + 'نصب کنندهٔ کستوپاد', + 'manual_config' => 'پیکربندی دستی', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'پیکربندی نمونه', + 'hostname' => 'نام میزبان', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'نام میزبان پایگاه داده', + 'db_name' => 'نام پایگاه‌داده', + 'db_username' => 'نام کاربری پایگاه‌داده', + 'db_password' => 'گذرواژهٔ پایگاه‌داده', + 'db_prefix' => 'پيشوند پايگاه‌داده', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'پیکربندی انباره', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'پرونده', + 'redis' => 'ردیس', + 'predis' => 'Predis', + ], + 'next' => 'بعدی', + 'submit' => 'پایان نصب', + 'create_superadmin' => 'ایجاد ابرحساب مدیریتان', + 'email' => 'رایانامه', + 'username' => 'نام‌کاربری', + 'password' => 'گذرواژه', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/fr-ca/Install.php b/modules/Install/Language/fr-ca/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/fr-ca/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/fr/Install.php b/modules/Install/Language/fr/Install.php new file mode 100644 index 00000000..de3c99d7 --- /dev/null +++ b/modules/Install/Language/fr/Install.php @@ -0,0 +1,62 @@ + 'Assistant d’installation Castopod', + 'manual_config' => 'Configuration manuelle', + 'manual_config_subtitle' => + 'Créez un fichier `.env` qui contient tous vos paramètres puis rafraichissez la page pour continuer l’installation.', + 'form' => [ + 'instance_config' => 'Paramètres de l’instance', + 'hostname' => 'Nom d’hôte', + 'media_base_url' => 'Adresse racine des médias', + 'media_base_url_hint' => + 'Si vous utilisez un CDN vous pouvez les définir ici.', + 'admin_gateway' => 'Adresse d’administration', + 'admin_gateway_hint' => + 'Le chemin pour accéder à l’administration (par exemple https://example.com/cp-admin). Il est défini par défaut à cp-admin, nous vous recommandons de le changer par mesure de sécurité.', + 'auth_gateway' => 'Adresse d’authentification', + 'auth_gateway_hint' => + 'Le chemin des pages d’authentication (par exemple https://example.fr/cp-auth). Il est défini par défaut à cp-auth, nous vous recommandons de le changer par mesure de sécurité.', + 'database_config' => 'Paramètres de base de données', + 'database_config_hint' => + 'Castopod doit se connecter à votre base de données MySQL (ou MariaDB). Si vous ne disposez pas de ces informations, merci de contacter l’administrateur du serveur.', + 'db_hostname' => 'Nom d’hôte (ou IP) de la base de données', + 'db_name' => 'Nom de la base de données', + 'db_username' => 'Utilisateur de base de données', + 'db_password' => 'Mot de passe de base de données', + 'db_prefix' => 'Préfixe des tables', + 'db_prefix_hint' => + "Le préfixe des noms de tables de Castopod, laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.", + 'cache_config' => 'Paramètres de cache', + 'cache_config_hint' => + 'Sélectionnez votre gestionnaire de cache préféré. Laissez la valeur par défaut si vous ne savez pas de quoi il s’agit.', + 'cache_handler' => 'Gestionnaire de cache', + 'cacheHandlerOptions' => [ + 'file' => 'Fichiers', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Suivant', + 'submit' => 'Terminer l’installation', + 'create_superadmin' => 'Créer un compte super-utilisateur', + 'email' => 'E-mail', + 'username' => 'Identifiant', + 'password' => 'Mot de passe', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Le compte super-utilisateur a bien été créé. Connectez-vous et commencez à podcaster !', + 'databaseConnectError' => + 'Castopod n’a pas pu se connecter à la base de données. Modifier les paramètres de base de données et essayer à nouveau.', + 'writeError' => + "Impossible de créer/écrire le fichier `.env`. Créez manuellement un fichier `.env` en copiant le modèle `.env.example` fourni avec Castopod.", + ], +]; diff --git a/modules/Install/Language/fr2/Install.php b/modules/Install/Language/fr2/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/fr2/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/gd/Install.php b/modules/Install/Language/gd/Install.php new file mode 100644 index 00000000..2c39010f --- /dev/null +++ b/modules/Install/Language/gd/Install.php @@ -0,0 +1,62 @@ + 'Inneal-stàlaidh Chastopod', + 'manual_config' => 'Rèiteachadh a làimh', + 'manual_config_subtitle' => + 'Cruthaich faidhle `.env` leis na roghainnean agad agus ath-nuadhaich an duilleag a leantainn air adhart leis an stàladh.', + 'form' => [ + 'instance_config' => 'Rèiteachadh an ionstans', + 'hostname' => 'Ainm an òstair', + 'media_base_url' => 'URL bunaiteach nam meadhanan', + 'media_base_url_hint' => + 'Ma tha thu a’ cleachdadh CDN agus/no seirbheis anailiseachd air an taobh a-muigh, faodaidh tu an suidheachadh an-seo.', + 'admin_gateway' => 'Balach na rianachd', + 'admin_gateway_hint' => + 'Seo an t-slighe airson raon na rianachd inntrigeadh (m.e. https://ball-eisimpleir.com/cp-admin). Thèid seo a shuidheachadh air cp-admin a ghnàth ach mholamaid gun atharraich thu seo air adhbhar tèarainteachd.', + 'auth_gateway' => 'Bealach an dearbhaidh', + 'auth_gateway_hint' => + 'Seo an t-slighe airson duilleagan an dearbhaidh inntrigeadh (m.e. https://ball-eisimpleir.com/cp-auth). Thèid seo a shuidheachadh air cp-auth a ghnàth ach mholamaid gun atharraich thu seo air adhbhar tèarainteachd.', + 'database_config' => 'Rèiteachadh an stòir-dhàta', + 'database_config_hint' => + 'Feumaidh Castopod ceangal ris an stòr-dàta MySQL (no MariaDB) agad. Mur eil am fiosrachadh riatanach seo agad, cuir fios tu rianaire an fhrithealaiche agad.', + 'db_hostname' => 'Ainm òstair an stòir-dhàta', + 'db_name' => 'Ainm an stòir-dhàta', + 'db_username' => 'Ainm-cleachdaiche an stòir-dhàta', + 'db_password' => 'Facal-faire an stòir-dhàta', + 'db_prefix' => 'Ro-leasachan an stòir-dhàta', + 'db_prefix_hint' => + "Seo ro-leasachan do dh’ainmean clàran Chastopod, fàg e mar a tha e mur eil thu a’ tuigsinn dè as ciall dha.", + 'cache_config' => 'Rèiteachadh an tasgadain', + 'cache_config_hint' => + 'Tagh an làimhsichear as fheàrr leat dhan tasgadan. Fàg air an luach bhunaiteach e mur eil thu a’ tuigsinn dè as ciall dha.', + 'cache_handler' => 'Làimhsichear an tasgadain', + 'cacheHandlerOptions' => [ + 'file' => 'Faidhle', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Air adhart', + 'submit' => 'Cuir crìoch air an stàladh', + 'create_superadmin' => 'Cruthaich an cunntas sàr-rianaire agad', + 'email' => 'Post-d', + 'username' => 'Ainm-cleachdaiche', + 'password' => 'Facal-faire', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Chaidh an cunntas sàr-rianaire agad a chruthachadh. Clàraich a-steach a thòiseachadh leis a’ phod-chraoladh!', + 'databaseConnectError' => + 'Cha b’ urrainn do Chastopod ceangal ris an stòr-dàta agad. Deasaich rèiteachadh an stòir-dhàta agad is feuch ris a-rithist.', + 'writeError' => + "Cha b’ urrainn dhuinn am faidhle `.env` a chruthachadh/sgrìobhadh thuige. Feumaidh tu a chruthachadh a làimh a leantainn ris an fhaidhle-teamplaid `.env.example` sa phacaid Castopod.", + ], +]; diff --git a/modules/Install/Language/gl/Install.php b/modules/Install/Language/gl/Install.php new file mode 100644 index 00000000..74c46c3b --- /dev/null +++ b/modules/Install/Language/gl/Install.php @@ -0,0 +1,62 @@ + 'Instalador de Castopod', + 'manual_config' => 'Configuración manual', + 'manual_config_subtitle' => + 'Crea un ficheiro `.env` cos teus axustes e actualiza a páxina para continuar coa instalación.', + 'form' => [ + 'instance_config' => 'Configuración da instancia', + 'hostname' => 'Servidor', + 'media_base_url' => 'URL base do multimedia', + 'media_base_url_hint' => + 'Se usas unha CDN e/ou un servizo externo de análise, debes indicalo aquí.', + 'admin_gateway' => 'Pasarela de administración', + 'admin_gateway_hint' => + 'A ruta para acceder á área de administración (ex. https://exemplo.com/cp-admin). Por defecto establécese cp-admin, recomendámosche cambialo por razóns de seguridade.', + 'auth_gateway' => 'Pasarela de autenticación', + 'auth_gateway_hint' => + 'A ruta para acceder á páxina de autenticación (ex. https://exemplo.com/cp-auth). Por defecto establécese como cp-auth, pero recomendámosche cambialo por razóns de seguridade.', + 'database_config' => 'Configuración da base de datos', + 'database_config_hint' => + 'Castopod precisa conectar coa túa base de datos MySQL (ou MariaDB). Se no tes esta información, contacta coa administración do teu servidor.', + 'db_hostname' => 'Servidor da base de datos', + 'db_name' => 'Nome da base de datos', + 'db_username' => 'Usuaria da base de datos', + 'db_password' => 'Contrasinal da base de datos', + 'db_prefix' => 'Prefix da base de datos', + 'db_prefix_hint' => + "O prefix dos nomes das táboas Castopod, déixao como está se non sabes o significa.", + 'cache_config' => 'Configuración da caché', + 'cache_config_hint' => + 'Elixe o xestor da caché preferido. Deixa o valor por defecto se non sabes o que significa.', + 'cache_handler' => 'Xestor da cache', + 'cacheHandlerOptions' => [ + 'file' => 'Ficheiro', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Seguinte', + 'submit' => 'Rematar instalación', + 'create_superadmin' => 'Crea a conta de superadministración', + 'email' => 'Email', + 'username' => 'Identificador', + 'password' => 'Contrasinal', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'A conta de superadministración creouse correctamente. Accede para comezar a publicar!', + 'databaseConnectError' => + 'Castopod non pode conectar coa base de datos. Edita a configuración da base de datos e inténtao outra vez.', + 'writeError' => + "Non se puido crear/escribir o ficheiro `.env`. Tes que crealo manualmente seguindo o modelo `.env.example` incluído no paquete Castopod.", + ], +]; diff --git a/modules/Install/Language/id/Install.php b/modules/Install/Language/id/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/id/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/it/Install.php b/modules/Install/Language/it/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/it/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/ja/Install.php b/modules/Install/Language/ja/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/ja/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/kk/Install.php b/modules/Install/Language/kk/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/kk/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/ko/Install.php b/modules/Install/Language/ko/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/ko/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/nl/Install.php b/modules/Install/Language/nl/Install.php new file mode 100644 index 00000000..e5cc6d4a --- /dev/null +++ b/modules/Install/Language/nl/Install.php @@ -0,0 +1,62 @@ + 'Castopod installatie', + 'manual_config' => 'Handmatige configuratie', + 'manual_config_subtitle' => + 'Maak een `.env` bestand aan met je instellingen en vernieuw de pagina om door te gaan met de installatie.', + 'form' => [ + 'instance_config' => 'Instantie configuratie', + 'hostname' => 'Hostnaam', + 'media_base_url' => 'Media basis-URL', + 'media_base_url_hint' => + 'Als u een CDN en/of een externe statistiekenservice gebruikt, kunt u ze hier instellen.', + 'admin_gateway' => 'Admin pad', + 'admin_gateway_hint' => + 'De route naar toegang tot de admin omgeving (bijv. https://example.com/cp-admin). Het is standaard ingesteld als cp-admin, we raden je aan om het te wijzigen om veiligheidsredenen.', + 'auth_gateway' => 'Authenticatie pad', + 'auth_gateway_hint' => + 'De route voor toegang tot de authenticatiepagina\'s (bijv. https://example.com/cp-auth). Deze is standaard ingesteld als cp-auth, wij raden u aan deze om veiligheidsredenen te wijzigen.', + 'database_config' => 'Databaseconfiguratie', + 'database_config_hint' => + 'Castopod moet verbinding maken met uw MySQL (of MariaDB) database. Als u niet over de benodigde informatie beschikt, neem dan contact op met uw serverbeheerder.', + 'db_hostname' => 'Database hostnaam', + 'db_name' => 'Databasenaam', + 'db_username' => 'Database gebruikersnaam', + 'db_password' => 'Database wachtwoord', + 'db_prefix' => 'Database voorvoegsel', + 'db_prefix_hint' => + "Het voorvoegsel van de Castopod tabelnamen. Laat leeg indien je niet weet wat dit betekent.", + 'cache_config' => 'Cache-configuratie', + 'cache_config_hint' => + 'Kies je gewenste cache-handler. Laat deze standaard waarde achter als je geen idee hebt wat het betekent.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'Bestandsysteem', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Volgende', + 'submit' => 'Installatie voltooien', + 'create_superadmin' => 'Maak uw Super Admin account aan', + 'email' => 'E-mail', + 'username' => 'Gebruikersnaam', + 'password' => 'Wachtwoord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Uw superadmin account is aangemaakt. Log in om met podcasten te starten!', + 'databaseConnectError' => + 'Castopod kon geen verbinding maken met uw database. Bewerk uw databaseconfiguratie en probeer het opnieuw.', + 'writeError' => + "Kon het `.env` bestand niet maken/schrijven. Je moet het handmatig aanmaken door het meegeleverde voorbeeld `.env.example` bestand te kopiëren en aan te passen.", + ], +]; diff --git a/modules/Install/Language/nn-no/Install.php b/modules/Install/Language/nn-no/Install.php new file mode 100644 index 00000000..46c72d25 --- /dev/null +++ b/modules/Install/Language/nn-no/Install.php @@ -0,0 +1,62 @@ + 'Castopod-installering', + 'manual_config' => 'Manuelt oppsett', + 'manual_config_subtitle' => + 'Lag ei `.env`-fil med innstillingane dine og oppdater sida for å halda fram installasjonen.', + 'form' => [ + 'instance_config' => 'Oppsett for nettstaden', + 'hostname' => 'Vertsnamn', + 'media_base_url' => 'Mediabase-URL', + 'media_base_url_hint' => + 'Viss du bruker eit leveringsnettverk (CDN) og/eller ei ekstern analysetenest, kan du skriva dei inn her.', + 'admin_gateway' => 'Innfallsport for styrar', + 'admin_gateway_hint' => + 'Ruta for å koma til styringsområdet (td. https://eksempel.no/cp-admin). Standardvalet er cp-admin, me tilrår at du endrar det av omsyn til tryggleiken.', + 'auth_gateway' => 'Innfallsport for autentisering', + 'auth_gateway_hint' => + 'Ruta for å koma til autentiseringssidene (td. https://eksempel.no/cp-auth). Standardvalet er cp-auth, me tilrår at du endrar det av omsyn til tryggleiken.', + 'database_config' => 'Databaseoppsett', + 'database_config_hint' => + 'Castopod treng å kopla seg til MySQL (eller MariaDB)-databasen din. Viss du ikkje har opplysingane som trengst, må du kontakta systemansvarleg.', + 'db_hostname' => 'Databasevertsnamn', + 'db_name' => 'Databasenamn', + 'db_username' => 'Databasebrukarnamn', + 'db_password' => 'Databasepassord', + 'db_prefix' => 'Databaseprefiks', + 'db_prefix_hint' => + "Prefikset til Castopod-tabellane. La det stå om du ikkje veit kva det tyder.", + 'cache_config' => 'Mellomlagringsoppsett', + 'cache_config_hint' => + 'Vel korleis du vil handtera mellomlageret. La stå som det er om du ikkje veit kva det tyder.', + 'cache_handler' => 'Mellomlagerhandtering', + 'cacheHandlerOptions' => [ + 'file' => 'Fil', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Neste', + 'submit' => 'Fullfør installeringa', + 'create_superadmin' => 'Lag superstyrar-konto', + 'email' => 'Epost', + 'username' => 'Brukarnamn', + 'password' => 'Passord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Superstyrar-kontoen din er oppretta. Logg inn for å byrja med podkasting!', + 'databaseConnectError' => + 'Castopod greidde ikkje å kopla til databasen din. Sjå gjennom databaseoppsettet og prøv ein gong til.', + 'writeError' => + "Greidde ikkje laga eller skriva til `.env`-fila. Du må laga ho manuelt ved å fylgja `.env.example`-filmalen i Castopod-pakka.", + ], +]; diff --git a/modules/Install/Language/oc/Install.php b/modules/Install/Language/oc/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/oc/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/pl/Install.php b/modules/Install/Language/pl/Install.php new file mode 100644 index 00000000..aa214368 --- /dev/null +++ b/modules/Install/Language/pl/Install.php @@ -0,0 +1,62 @@ + 'Instalator Castopod', + 'manual_config' => 'Konfiguracja ręczna', + 'manual_config_subtitle' => + 'Stwórz plik `.env` ze swoimi ustawieniami i odśwież stronę, aby kontynuować instalację.', + 'form' => [ + 'instance_config' => 'Konfiguracja instancji', + 'hostname' => 'Nazwa hosta', + 'media_base_url' => 'Bazowy URL mediów', + 'media_base_url_hint' => + 'Jeśli korzystasz z CDNa i/lub zewnętrznej usługi analitycznej, możesz ustawić je tutaj.', + 'admin_gateway' => 'Strona administracyjna', + 'admin_gateway_hint' => + 'Dostęp do obszaru administracyjnego (np. https://example.com/cp-admin). Domyślnie jest ustawiony jako cp-admin, ale ze względów bezpieczeństwa zalecamy zmianę tej nazwy.', + 'auth_gateway' => 'Strona uwierzytelniania', + 'auth_gateway_hint' => + 'Dostęp do stron uwierzytelniających (np. https://example.com/cp-auth). Domyślnie jest ustawiony jako cp-auth, ale ze względów bezpieczeństwa zalecamy zmianę tej nazwy.', + 'database_config' => 'Konfiguracja bazy danych', + 'database_config_hint' => + 'Castopod musi połączyć się z bazą danych MySQL (lub MariaDB). Jeśli nie masz tych wymaganych informacji, skontaktuj się z administratorem serwera.', + 'db_hostname' => 'Nazwa hosta bazy danych', + 'db_name' => 'Nazwa bazy danych', + 'db_username' => 'Nazwa użytkownika bazy danych', + 'db_password' => 'Hasło bazy danych', + 'db_prefix' => 'Prefiks bazy danych', + 'db_prefix_hint' => + "Prefiks nazw tabel Castopod — pozostaw bez zmian, jeśli nie wiesz, co to znaczy.", + 'cache_config' => 'Konfiguracja pamięci podręcznej', + 'cache_config_hint' => + 'Wybierz preferowany mechanizm pamięci podręcznej. Zostaw domyślną wartość, jeśli nie masz pojęcia, co to znaczy.', + 'cache_handler' => 'Mechanizm pamięci podręcznej', + 'cacheHandlerOptions' => [ + 'file' => 'Plik', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Dalej', + 'submit' => 'Zakończ instalację', + 'create_superadmin' => 'Utwórz swoje konto superadministratora', + 'email' => 'Email', + 'username' => 'Nazwa użytkownika', + 'password' => 'Hasło', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Twoje konto superadministratora zostało pomyślnie utworzone. Zaloguj się, aby rozpocząć podcastowanie!', + 'databaseConnectError' => + 'Castopod nie mógł się połączyć z Twoją bazą danych. Edytuj konfigurację bazy danych i spróbuj ponownie.', + 'writeError' => + "Nie można utworzyć/zapisać pliku `.env`. Musisz go utworzyć ręcznie, postępując zgodnie z szablonem `.env.example` w pakiecie Castopod.", + ], +]; diff --git a/modules/Install/Language/pt-br/Install.php b/modules/Install/Language/pt-br/Install.php new file mode 100644 index 00000000..c444479e --- /dev/null +++ b/modules/Install/Language/pt-br/Install.php @@ -0,0 +1,62 @@ + 'Instalador do Castopod', + 'manual_config' => 'Configuração manual', + 'manual_config_subtitle' => + 'Crie um arquivo `.env` com suas configurações e atualize a página para continuar a instalação.', + 'form' => [ + 'instance_config' => 'Configuração da instância', + 'hostname' => 'Hostname', + 'media_base_url' => 'URL de banco de mídia', + 'media_base_url_hint' => + 'Se você usar um CDN, você pode configurar aqui.', + 'admin_gateway' => 'Gateway de administrador', + 'admin_gateway_hint' => + 'O caminho para acessar a área admin (ex. https://example.com/cp-admin). Ele é definido por padrão como cp-admin, recomendamos que você a altere por razões de segurança.', + 'auth_gateway' => 'Gateway de autenticação', + 'auth_gateway_hint' => + 'O caminho para acessar as páginas de autenticação (ex. https://example.com/cp-auth). Ele é definido por padrão como cp-auth, recomendamos que você a altere por motivos de segurança.', + 'database_config' => 'Configuração do banco de dados', + 'database_config_hint' => + 'O Castopod precisa se conectar ao seu banco de dados MySQL (ou MariaDB). Se você não tem essas informações necessárias, entre em contato com o administrador do servidor.', + 'db_hostname' => 'Hostname do banco de dados', + 'db_name' => 'Nome do banco de dados', + 'db_username' => 'Nome de usuário do banco de dados', + 'db_password' => 'Senha do banco de dados', + 'db_prefix' => 'Prefixo do banco de dados', + 'db_prefix_hint' => + "O prefixo dos nomes das tabelas do Castopod, deixe como está se você não souber o que significa.", + 'cache_config' => 'Configuração de cache', + 'cache_config_hint' => + 'Escolha seu manipulador de cache preferido. Deixe-o com o valor padrão se você não tiver idéia do que ele significa.', + 'cache_handler' => 'Manipulador de cache (cache handler)', + 'cacheHandlerOptions' => [ + 'file' => 'Arquivo', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Avançar', + 'submit' => 'Finalizar instalação', + 'create_superadmin' => 'Criar sua conta de superadmin', + 'email' => 'E-mail', + 'username' => 'Nome de usuário', + 'password' => 'Senha', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Sua conta superadmin foi criada com sucesso. Entre para começar a podcastar!', + 'databaseConnectError' => + 'O Castopod não pôde se conectar ao seu banco de dados. Edite sua configuração do banco de dados e tente novamente.', + 'writeError' => + "Não foi possível criar/escrever o arquivo `.env`. Você deve criá-lo manualmente, seguindo o template do arquivo `.env.example` no pacote Castopod.", + ], +]; diff --git a/modules/Install/Language/pt/Install.php b/modules/Install/Language/pt/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/pt/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/ro/Install.php b/modules/Install/Language/ro/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/ro/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/ru/Install.php b/modules/Install/Language/ru/Install.php new file mode 100644 index 00000000..1f66ef11 --- /dev/null +++ b/modules/Install/Language/ru/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/sk/Install.php b/modules/Install/Language/sk/Install.php new file mode 100644 index 00000000..d6eaaf2d --- /dev/null +++ b/modules/Install/Language/sk/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Nastavenie databázy', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Názov databázy', + 'db_username' => 'Prihlasovacie meno do databázy', + 'db_password' => 'Heslo k databáze', + 'db_prefix' => 'Prefix databázy', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Ďalej', + 'submit' => 'Dokončiť inštaláciu', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Email', + 'username' => 'Používateľské meno', + 'password' => 'Heslo', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod sa nemohol pripojiť k vašej databáze. Upravte konfiguráciu svojej databázy a skúste to znovu.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Install/Language/sr-latn/Install.php b/modules/Install/Language/sr-latn/Install.php new file mode 100644 index 00000000..d12ba554 --- /dev/null +++ b/modules/Install/Language/sr-latn/Install.php @@ -0,0 +1,62 @@ + 'Instalator Castopoda', + 'manual_config' => 'Ručna konfiguracija', + 'manual_config_subtitle' => + 'Napravite `.env` datoteku sa vašim podešavanjima i osvežite stranicu da bi ste nastavili instalaciju.', + 'form' => [ + 'instance_config' => 'Konfiguracija instance', + 'hostname' => 'Ime domaćina', + 'media_base_url' => 'URL medijske baze', + 'media_base_url_hint' => + 'Ako koristite CDN i/ili eksternu uslugu za analitiku, možete ih postaviti ovde.', + 'admin_gateway' => 'Administratorski izlaz', + 'admin_gateway_hint' => + 'Ruta za pristup kontrolnoj tabli administratora (eg. https://example.com/cp-admin).Podrazumevano je podešena na cp-admin, preporučujemo da je promenite iz sigurnosnih razloga.', + 'auth_gateway' => 'Auth izlaz', + 'auth_gateway_hint' => + 'Ruta za pristup stranicama za potvrdu identiteta (eg. https://example.com/cp-auth).Podrazumevano je podešena na cp-auth, preporučujemo da je promenite iz sigurnosnih razloga.', + 'database_config' => 'Konfiguracija baze podataka', + 'database_config_hint' => + 'Castopod mora da se poveže za vašom MySQL (ili MariaDB) bazom. Ukoliko ne posedujete potrebne informacije, molimo vas kontaktirajte administratora vašeg servera.', + 'db_hostname' => 'Ime hosta baze podataka', + 'db_name' => 'Ime baze podataka', + 'db_username' => 'Korisničko ime baze podataka', + 'db_password' => 'Lozinka baze podataka', + 'db_prefix' => 'Prefiks baze', + 'db_prefix_hint' => + "Prefiks imena tabela Castopod-a, ne diraj ako ne znaš šta znači.", + 'cache_config' => 'Konfiguracija keša', + 'cache_config_hint' => + 'Izaberite željeni obrađivač keša. Ostavite je kao podrazumevanu vrednost ako nemate pojma šta to znači.', + 'cache_handler' => 'Obrađivač keša', + 'cacheHandlerOptions' => [ + 'file' => 'Datoteka', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Sledeće', + 'submit' => 'Završi instalaciju', + 'create_superadmin' => 'Kreiraj svoj nalog super administratora', + 'email' => 'E-pošta', + 'username' => 'Korisničko ime', + 'password' => 'Lozinka', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Vaš nalog superadmina je uspešno kreiran. Prijavite se da biste započeli podkasting!', + 'databaseConnectError' => + 'Castopod nije mogao da se poveže sa vašom bazom podataka. Uredite konfiguraciju baze podataka i pokušajte ponovo.', + 'writeError' => + "Nije moguće kreirati/upisati datoteku `.env`. Morate je kreirati ručno prateći šablon datoteke `.env.example` u Castopod-ovom paketu.", + ], +]; diff --git a/modules/Install/Language/sv/Install.php b/modules/Install/Language/sv/Install.php new file mode 100644 index 00000000..f2bc70b5 --- /dev/null +++ b/modules/Install/Language/sv/Install.php @@ -0,0 +1,62 @@ + 'Installationsprogrammet för Castopod', + 'manual_config' => 'Manuell konfiguration', + 'manual_config_subtitle' => + 'Skapa en \'.env\' fil med dina inställningar och uppdatera sidan för att fortsätta installationen.', + 'form' => [ + 'instance_config' => 'Konfiguration av instans', + 'hostname' => 'Servernamn', + 'media_base_url' => 'Bas-URL för media', + 'media_base_url_hint' => + 'Om du använder en CDN och/eller en extern analystjänst kan du ställa in dem här.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'Rutten för att komma åt adminområdet (t.ex. https://example.com/cp-admin). Det är som standard inställt som cp-admin, vi rekommenderar att du ändrar det av säkerhetsskäl.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'Rutten för att komma åt autentiseringssidorna (t.ex. https://example.com/cp-auth). Den är som standard inställd som cp-auth, vi rekommenderar att du ändrar den av säkerhetsskäl.', + 'database_config' => 'Databas konfiguration', + 'database_config_hint' => + 'Castopod måste ansluta till din MySQL (eller MariaDB) databas. Om du inte har dessa nödvändiga uppgifter, kontakta din serveradministratör.', + 'db_hostname' => 'Databasens värdnamn', + 'db_name' => 'Databasnamn', + 'db_username' => 'Användarnamn till databasen', + 'db_password' => 'Databasens lösenord', + 'db_prefix' => 'Databas prefix', + 'db_prefix_hint' => + "Prefixet för Castopod tabellnamn, lämna som om du inte vet vad det betyder.", + 'cache_config' => 'Cache-konfiguration', + 'cache_config_hint' => + 'Välj önskad cachehanterare. Lämna det som standardvärde om du inte har någon aning om vad det innebär.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'Fil', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Nästa', + 'submit' => 'Slutför installationen', + 'create_superadmin' => 'Create your superadmin account', + 'email' => 'Epost', + 'username' => 'Användarnamn', + 'password' => 'Lösenord', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ditt superadministratörskonto har skapats. Logga in för att starta podcasting!', + 'databaseConnectError' => + 'Castopod kunde inte ansluta till din databas. Redigera din databaskonfiguration och försök igen.', + 'writeError' => + "Kunde inte skapa/skriva `.env`-filen. Du måste skapa den manuellt genom att följa filmallen `.env.exempel` i Castopod-paketet.", + ], +]; diff --git a/modules/Install/Language/uk/Install.php b/modules/Install/Language/uk/Install.php new file mode 100644 index 00000000..a06569bb --- /dev/null +++ b/modules/Install/Language/uk/Install.php @@ -0,0 +1,62 @@ + 'Кастопод інсталятор', + 'manual_config' => 'Ручне налаштування', + 'manual_config_subtitle' => + 'Створіть файл `.env` з налаштуваннями та перезавантажте сторінку, щоб продовжити встановлення.', + 'form' => [ + 'instance_config' => 'Конфігурація екземпляру', + 'hostname' => 'Ім\'я хоста', + 'media_base_url' => 'URL-адреса бази даних медіа', + 'media_base_url_hint' => + 'Якщо ви використовуєте CDN та/або зовнішній аналітичний сервіс, ви можете встановити їх тут.', + 'admin_gateway' => 'Шлюз Адміністратора', + 'admin_gateway_hint' => + 'Шлях до сторінки аутентифікації (наприклад https://example.com/cp-admin). Встановлений за замовчуванням cp-auth, Ми рекомендуємо вам змінити його з міркувань безпеки.', + 'auth_gateway' => 'Шлюз авторизації', + 'auth_gateway_hint' => + 'Шлях до сторінки аутентифікації (наприклад https://example.com/cp-auth). Встановлений за замовчуванням cp-auth, Ми рекомендуємо вам змінити його з міркувань безпеки.', + 'database_config' => 'Налаштування бази даних', + 'database_config_hint' => + 'Кастопод потребує підключення до бази даних MySQL (або MariaDB) для відновлення. Якщо у вас немає такої необхідної інформації, будь ласка, зверніться до адміністратора вашого сервера.', + 'db_hostname' => 'Ім\'я хоста бази даних', + 'db_name' => 'Назва бази даних', + 'db_username' => 'Ім\'я користувача бази даних', + 'db_password' => 'Пароль бази даних', + 'db_prefix' => 'Префікс бази даних', + 'db_prefix_hint' => + "Залишайте префікс імен таблиць Castopod, якщо ви не знаєте що це значить.", + 'cache_config' => 'Конфігурація кешу', + 'cache_config_hint' => + 'Виберіть бажаний обробник кешу або залиште без змін, як стандартне значення, якщо ви не знаєте, що це означає.', + 'cache_handler' => 'Обробник кешу', + 'cacheHandlerOptions' => [ + 'file' => 'Файл', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Далі', + 'submit' => 'Завершити установку', + 'create_superadmin' => 'Створіть свій обліковий запис головного адміністратора', + 'email' => 'Пошта', + 'username' => 'Ім\'я користувача', + 'password' => 'Пароль', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Ваш обліковий запис головного адміністратора було успішно створено. Увійдіть, щоб почати подкасти!', + 'databaseConnectError' => + 'Castopod не зміг під\'єднатися до вашої бази даних. Перевірте конфігурацію бази даних і повторіть спробу.', + 'writeError' => + "Не вдалося створити/записати файл `.env`. Ви повинні створити його вручну, перейшовши шаблон файлу `.env.example` в пакеті Castopode.", + ], +]; diff --git a/modules/Install/Language/zh-hans/Install.php b/modules/Install/Language/zh-hans/Install.php new file mode 100644 index 00000000..822cf2f3 --- /dev/null +++ b/modules/Install/Language/zh-hans/Install.php @@ -0,0 +1,62 @@ + 'Castopod 安装程序', + 'manual_config' => '手动配置', + 'manual_config_subtitle' => + '创建一个带有你设置的“.env”文件,并刷新页面以继续安装。', + 'form' => [ + 'instance_config' => '实例配置', + 'hostname' => '主机名', + 'media_base_url' => '媒体基础URL', + 'media_base_url_hint' => + '如果你使用 CDN 或外部分析服务,可以在此处设置它们。', + 'admin_gateway' => '管理网关', + 'admin_gateway_hint' => + '访问管理区域的路由(例如,https://example.com/cp-admin)。默认设置为 cp-admin,处于安全考虑,建议你修改它。', + 'auth_gateway' => '认证网关', + 'auth_gateway_hint' => + '访问认证页面的路由(例如,https://example.com/cp-auth)。默认设置为 cp-auth,处于安全考虑,建议你修改它。', + 'database_config' => '数据库配置', + 'database_config_hint' => + 'Castopod 需要连接到你的 MySQL (or MariaDB) 数据库。如果你没有这些信息,请联系你的服务器管理员。', + 'db_hostname' => '数据库主机', + 'db_name' => '数据库名', + 'db_username' => '数据库用户名', + 'db_password' => '数据库密码', + 'db_prefix' => '数据库前缀', + 'db_prefix_hint' => + "Castopod 表名的前缀,如果你不知道它的含义,请保留默认值。", + 'cache_config' => '缓存配置', + 'cache_config_hint' => + '选择你喜欢的缓存处理程序。如果你不知道它的含义,请保持默认值。', + 'cache_handler' => '缓存处理程序', + 'cacheHandlerOptions' => [ + 'file' => '文件', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => '下一步', + 'submit' => '完成安装', + 'create_superadmin' => '创建你的超级管理员帐户', + 'email' => '邮箱', + 'username' => '用户名', + 'password' => '密码', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + '您的超级管理员帐户已创建。登录以开始播客!', + 'databaseConnectError' => + 'Castopod 无法连接到你的数据库。编辑你的数据库配置,然后重试。', + 'writeError' => + "无法创建或写入 `.env` 文件。你必须手动按照 Castopod 中的 `.env.example` 文件模板创建它。", + ], +]; diff --git a/modules/Install/Language/zh-hant/Install.php b/modules/Install/Language/zh-hant/Install.php new file mode 100644 index 00000000..45d26085 --- /dev/null +++ b/modules/Install/Language/zh-hant/Install.php @@ -0,0 +1,62 @@ + 'Castopod installer', + 'manual_config' => 'Manual configuration', + 'manual_config_subtitle' => + 'Create a `.env` file with your settings and refresh the page to continue installation.', + 'form' => [ + 'instance_config' => 'Instance configuration', + 'hostname' => 'Hostname', + 'media_base_url' => 'Media base URL', + 'media_base_url_hint' => + 'If you use a CDN and/or an external analytics service, you may set them here.', + 'admin_gateway' => 'Admin gateway', + 'admin_gateway_hint' => + 'The route to access the admin area (eg. https://example.com/cp-admin). It is set by default as cp-admin, we recommend you change it for security reasons.', + 'auth_gateway' => 'Auth gateway', + 'auth_gateway_hint' => + 'The route to access the authentication pages (eg. https://example.com/cp-auth). It is set by default as cp-auth, we recommend you change it for security reasons.', + 'database_config' => 'Database configuration', + 'database_config_hint' => + 'Castopod needs to connect to your MySQL (or MariaDB) database. If you do not have these required info, please contact your server administrator.', + 'db_hostname' => 'Database hostname', + 'db_name' => 'Database name', + 'db_username' => 'Database username', + 'db_password' => 'Database password', + 'db_prefix' => 'Database prefix', + 'db_prefix_hint' => + "The prefix of the Castopod table names, leave as is if you don't know what it means.", + 'cache_config' => 'Cache configuration', + 'cache_config_hint' => + 'Choose your preferred cache handler. Leave it as the default value if you have no clue what it means.', + 'cache_handler' => 'Cache handler', + 'cacheHandlerOptions' => [ + 'file' => 'File', + 'redis' => 'Redis', + 'predis' => 'Predis', + ], + 'next' => 'Next', + 'submit' => 'Finish install', + 'create_superadmin' => 'Create your Super Admin account', + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + ], + 'messages' => [ + 'createSuperAdminSuccess' => + 'Your superadmin account has been created successfully. Login to start podcasting!', + 'databaseConnectError' => + 'Castopod could not connect to your database. Edit your database configuration and try again.', + 'writeError' => + "Couldn't create/write the `.env` file. You must create it manually by following the `.env.example` file template in the Castopod package.", + ], +]; diff --git a/modules/Media/Config/Media.php b/modules/Media/Config/Media.php new file mode 100644 index 00000000..987847c4 --- /dev/null +++ b/modules/Media/Config/Media.php @@ -0,0 +1,73 @@ + + */ + public array $fileManagers = [ + 'fs' => FS::class, + 's3' => S3::class, + ]; + + /** + * @var array + */ + public array $s3 = [ + 'bucket' => 'castopod', + 'key' => '', + 'secret' => '', + 'region' => '', + 'protocol' => '', + 'endpoint' => '', + 'debug' => false, + 'pathStyleEndpoint' => false, + 'keyPrefix' => '', + ]; + + /** + * -------------------------------------------------------------------------- + * Media Base URL + * -------------------------------------------------------------------------- + * + * URL to your media root. Typically this will be your base URL, + * WITH a trailing slash: + * + * http://cdn.example.com/ + */ + public string $baseURL = 'http://localhost:8080/'; + + /** + * -------------------------------------------------------------------------- + * Media root folder + * -------------------------------------------------------------------------- + * Defines the root folder for media files storage + */ + public string $root = 'media'; + + /** + * -------------------------------------------------------------------------- + * Media storage folder + * -------------------------------------------------------------------------- + * Defines the folder used to store the media root folder + */ + public string $storage = ROOTPATH . 'public'; + + /** + * @var array + */ + public array $folders = [ + 'podcasts' => 'podcasts', + 'persons' => 'persons', + ]; +} diff --git a/modules/Media/Config/Services.php b/modules/Media/Config/Services.php new file mode 100644 index 00000000..8b5fd814 --- /dev/null +++ b/modules/Media/Config/Services.php @@ -0,0 +1,40 @@ +fileManagers[$config->fileManager]; + + $fileManager = new $fileManagerClass($config); + + if ($fileManager instanceof FileManagerInterface) { + return $fileManager; + } + + throw new Exception('File Manager service must extend FileManagerInterface'); + } +} diff --git a/modules/Media/Database/Migrations/2021-05-29-120000_add_media.php b/modules/Media/Database/Migrations/2021-05-29-120000_add_media.php new file mode 100644 index 00000000..d7409038 --- /dev/null +++ b/modules/Media/Database/Migrations/2021-05-29-120000_add_media.php @@ -0,0 +1,88 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'file_path' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'file_size' => [ + 'type' => 'INT', + 'unsigned' => true, + 'comment' => 'File size in bytes', + ], + 'file_mimetype' => [ + 'type' => 'VARCHAR', + 'constraint' => 45, + ], + 'file_metadata' => [ + 'type' => 'JSON', + 'null' => true, + ], + 'type' => [ + 'type' => 'ENUM', + 'constraint' => ['image', 'audio', 'video', 'transcript', 'chapters', 'document'], + 'default' => 'document', + ], + 'description' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'language_code' => [ + 'type' => 'VARCHAR', + 'constraint' => 2, + 'null' => true, + ], + 'uploaded_by' => [ + 'type' => 'INT', + 'constraint' => 11, + 'unsigned' => true, + ], + 'updated_by' => [ + 'type' => 'INT', + 'constraint' => 11, + 'unsigned' => true, + ], + 'uploaded_at' => [ + 'type' => 'DATETIME', + ], + 'updated_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addKey('id', true); + $this->forge->addUniqueKey('file_path'); + $this->forge->addForeignKey('uploaded_by', 'users', 'id'); + $this->forge->addForeignKey('updated_by', 'users', 'id'); + $this->forge->createTable('media'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('media'); + } +} diff --git a/modules/Media/Database/Migrations/2022-30-12-180000_rename_media_file_path.php b/modules/Media/Database/Migrations/2022-30-12-180000_rename_media_file_path.php new file mode 100644 index 00000000..14b54394 --- /dev/null +++ b/modules/Media/Database/Migrations/2022-30-12-180000_rename_media_file_path.php @@ -0,0 +1,43 @@ + [ + 'name' => 'file_key', + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]; + $this->forge->modifyColumn('media', $fields); + } + + #[Override] + public function down(): void + { + $fields = [ + 'file_key' => [ + 'name' => 'file_path', + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]; + $this->forge->modifyColumn('media', $fields); + } +} diff --git a/modules/Media/Entities/Audio.php b/modules/Media/Entities/Audio.php new file mode 100644 index 00000000..2219a537 --- /dev/null +++ b/modules/Media/Entities/Audio.php @@ -0,0 +1,54 @@ +file_metadata !== null) { + $this->duration = (float) $this->file_metadata['playtime_seconds']; + $this->header_size = (int) $this->file_metadata['avdataoffset']; + } + } + + #[Override] + public function setFile(File $file): self + { + parent::setFile($file); + + $getID3 = new GetID3(); + $audioMetadata = $getID3->analyze($file->getRealPath()); + + $this->attributes['file_mimetype'] = $audioMetadata['mime_type']; + $this->attributes['file_size'] = $audioMetadata['filesize']; + $this->attributes['description'] = @$audioMetadata['id3v2']['comments']['comment'][0]; + $this->attributes['file_metadata'] = json_encode([ + 'playtime_seconds' => $audioMetadata['playtime_seconds'], + 'avdataoffset' => $audioMetadata['avdataoffset'], + ], JSON_INVALID_UTF8_SUBSTITUTE); + + return $this; + } +} diff --git a/modules/Media/Entities/BaseMedia.php b/modules/Media/Entities/BaseMedia.php new file mode 100644 index 00000000..5eb1b118 --- /dev/null +++ b/modules/Media/Entities/BaseMedia.php @@ -0,0 +1,140 @@ +|null $file_metadata + * @property 'image'|'audio'|'video'|'document' $type + * @property string|null $description + * @property string|null $language_code + * @property int $uploaded_by + * @property int $updated_by + */ +class BaseMedia extends Entity +{ + protected File $file; + + /** + * @var list + */ + protected $dates = ['uploaded_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'id' => 'integer', + 'file_key' => 'string', + 'file_size' => 'int', + 'file_mimetype' => 'string', + 'file_metadata' => '?json-array', + 'type' => 'string', + 'description' => '?string', + 'language_code' => '?string', + 'uploaded_by' => 'integer', + 'updated_by' => 'integer', + ]; + + /** + * @param array $data + */ + #[Override] + public function injectRawData(array $data): static + { + parent::injectRawData($data); + + $this->initFileProperties(); + + return $this; + } + + public function initFileProperties(): void + { + $pathInfo = pathinfo($this->file_key) + [ + 'filename' => '', + 'dirname' => '', + 'extension' => '', + ]; + + $this->file_url = service('file_manager') + ->getUrl($this->file_key); + $this->file_name = $pathInfo['filename']; + $this->file_directory = $pathInfo['dirname']; + $this->file_extension = $pathInfo['extension']; + } + + public function setFile(File $file): self + { + $this->attributes['type'] = $this->type; + $this->attributes['file_mimetype'] = $file->getMimeType(); + $this->attributes['file_metadata'] = json_encode(lstat((string) $file), JSON_INVALID_UTF8_IGNORE); + + if ($filesize = $file->getSize()) { + $this->attributes['file_size'] = $filesize; + } + + $this->attributes['file'] = $file; + + return $this; + } + + public function saveFile(): void + { + if (! $this->attributes['file'] || ! $this->file_key) { + throw new RuntimeException("'file' and 'file_key' attributes must be set before saving a file."); + } + + $this->attributes['file_key'] = service('file_manager')->save($this->attributes['file'], $this->file_key); + } + + public function deleteFile(): bool + { + return service('file_manager')->delete($this->file_key); + } + + public function rename(): bool + { + $newFileKey = $this->file_directory . '/' . new File('')->getRandomName() . '.' . $this->file_extension; + + $db = db_connect(); + $db->transStart(); + + if (! new MediaModel()->update($this->id, [ + 'file_key' => $newFileKey, + ])) { + return false; + } + + if (! service('file_manager')->rename($this->file_key, $newFileKey)) { + $db->transRollback(); + + return false; + } + + $db->transComplete(); + + return true; + } +} diff --git a/modules/Media/Entities/Chapters.php b/modules/Media/Entities/Chapters.php new file mode 100644 index 00000000..44cbfc54 --- /dev/null +++ b/modules/Media/Entities/Chapters.php @@ -0,0 +1,65 @@ +file_metadata !== null && array_key_exists('chapter_count', $this->file_metadata)) { + helper('media'); + + $this->chapter_count = $this->file_metadata['chapter_count']; + } + } + + #[Override] + public function setFile(File $file): self + { + parent::setFile($file); + + $metadata = lstat((string) $file); + + if (! $metadata) { + $metadata = []; + } + + helper('filesystem'); + + $metadata['chapter_count'] = $this->countChaptersInJson($file); + + $this->attributes['file_metadata'] = json_encode($metadata, JSON_INVALID_UTF8_IGNORE); + + $this->file = $file; + + return $this; + } + + private function countChaptersInJson(File $file): Int + { + $chapterContent = file_get_contents($file->getRealPath()); + + if ($chapterContent === false) { + throw new Exception('Could not read chapter file at ' . $this->file->getRealPath()); + } + + return substr_count($chapterContent, 'startTime'); + } +} diff --git a/modules/Media/Entities/Document.php b/modules/Media/Entities/Document.php new file mode 100644 index 00000000..7a540862 --- /dev/null +++ b/modules/Media/Entities/Document.php @@ -0,0 +1,16 @@ +> $sizes + */ +class Image extends BaseMedia +{ + protected string $type = 'image'; + + /** + * @var array> + */ + protected array $sizes = []; + + #[Override] + public function initFileProperties(): void + { + parent::initFileProperties(); + + if ($this->file_metadata && array_key_exists('sizes', $this->file_metadata)) { + $this->sizes = $this->file_metadata['sizes']; + $this->initSizeProperties(); + } + } + + public function initSizeProperties(): bool + { + helper('filesystem'); + + foreach ($this->sizes as $name => $size) { + $extension = array_key_exists('extension', $size) ? $size['extension'] : $this->file_extension; + $mimetype = array_key_exists('mimetype', $size) ? $size['mimetype'] : $this->file_mimetype; + $width = array_key_exists('width', $size) ? $size['width'] : 0; + $height = array_key_exists('height', $size) ? $size['height'] : 0; + + $this->{$name . '_key'} = change_file_path($this->file_key, '_' . $name, $extension); + $this->{$name . '_url'} = service('file_manager')->getUrl($this->{$name . '_key'}); + $this->{$name . '_mimetype'} = $mimetype; + $this->{$name . '_width'} = $width; + $this->{$name . '_height'} = $height; + } + + return true; + } + + /** + * @param array $data + */ + #[Override] + public function injectRawData(array $data): static + { + parent::injectRawData($data); + + if ($this->attributes === []) { + return $this; + } + + if ($this->file_metadata !== [] && array_key_exists('sizes', $this->file_metadata)) { + $this->sizes = $this->file_metadata['sizes']; + $this->attributes['sizes'] = $this->file_metadata['sizes']; + $this->initFileProperties(); + $this->initSizeProperties(); + } + + return $this; + } + + #[Override] + public function setFile(File $file): self + { + parent::setFile($file); + + if ($this->file_mimetype === 'image/jpeg' && $metadata = @exif_read_data( + $file->getRealPath(), + null, + true, + )) { + $metadata['sizes'] = $this->attributes['sizes']; + $this->attributes['file_size'] = $metadata['FILE']['FileSize']; + } else { + $metadata = [ + 'sizes' => $this->attributes['sizes'], + ]; + } + + $this->attributes['file_metadata'] = json_encode($metadata, JSON_INVALID_UTF8_IGNORE); + + return $this; + } + + #[Override] + public function saveFile(): void + { + if ($this->attributes['sizes'] !== []) { + $this->initFileProperties(); + $this->saveSizes(); + } + + parent::saveFile(); + } + + #[Override] + public function deleteFile(): bool + { + if (parent::deleteFile()) { + return $this->deleteSizes(); + } + + return false; + } + + public function saveSizes(): void + { + $tempImagePath = ''; + if (! array_key_exists('file', $this->attributes) && $this->file_key) { + // no original file instance set to save sizes from + + // download image temporarily to generate sizes from + $tempImagePath = (string) tempnam(WRITEPATH . 'temp', 'img_'); + $imageContent = (string) service('file_manager') + ->getFileContents($this->file_key); + file_put_contents($tempImagePath, $imageContent); + + $this->attributes['file'] = new File($tempImagePath, true); + } + + // save derived sizes + $imageService = service('image'); + + foreach ($this->sizes as $name => $size) { + $tempFilePath = tempnam(WRITEPATH . 'temp', 'img_'); + $resizedImage = $imageService + ->withFile($this->attributes['file']->getRealPath()) + ->resize($size['width'], $size['height']); + + /** @var GdImage $resizedImageResource */ + $resizedImageResource = $resizedImage->getResource(); + + // set resolution to 72 by 72 for all sizes + // Apple Podcasts requires images to be 72 dpi + imageresolution($resizedImageResource, 72, 72); + + $resizedImage->save($tempFilePath); + + $newImage = new File($tempFilePath, true); + + service('file_manager') + ->save($newImage, $this->{$name . '_key'}); + } + + if ($tempImagePath !== '') { + unlink($tempImagePath); + } + } + + private function deleteSizes(): bool + { + // delete all derived sizes + foreach (array_keys($this->sizes) as $name) { + $pathProperty = $name . '_key'; + + if (! service('file_manager')->delete($this->{$pathProperty})) { + return false; + } + } + + return true; + } +} diff --git a/modules/Media/Entities/Transcript.php b/modules/Media/Entities/Transcript.php new file mode 100644 index 00000000..160d9551 --- /dev/null +++ b/modules/Media/Entities/Transcript.php @@ -0,0 +1,112 @@ +file_metadata !== null && array_key_exists('json_key', $this->file_metadata)) { + helper('media'); + + $this->json_key = $this->file_metadata['json_key']; + $this->json_url = service('file_manager') + ->getUrl($this->json_key); + } + } + + #[Override] + public function setFile(File $file): self + { + parent::setFile($file); + + $metadata = lstat((string) $file); + + if (! $metadata) { + $metadata = []; + } + + helper('filesystem'); + + // set metadata (generated json file path) + $this->json_key = change_file_path($this->file_key, '', 'json'); + $metadata['json_key'] = $this->json_key; + + $this->attributes['file_metadata'] = json_encode($metadata, JSON_INVALID_UTF8_IGNORE); + + $this->file = $file; + + return $this; + } + + #[Override] + public function saveFile(): void + { + $this->saveJsonTranscript(); + + parent::saveFile(); + } + + #[Override] + public function deleteFile(): bool + { + if (! parent::deleteFile()) { + return false; + } + + if ($this->json_key) { + return service('file_manager')->delete($this->json_key); + } + + return true; + } + + private function saveJsonTranscript(): void + { + $transcriptContent = file_get_contents($this->file->getRealPath()); + + $transcriptParser = new TranscriptParser(); + + if ($transcriptContent === false) { + throw new Exception('Could not read transcript file at ' . $this->file->getRealPath()); + } + + $transcript_format = $this->file->getExtension(); + $transcriptJson = match ($transcript_format) { + 'vtt' => $transcriptParser->loadString($transcriptContent) + ->parseVtt(), + default => $transcriptParser->loadString($transcriptContent) + ->parseSrt(), + }; + + $tempFilePath = WRITEPATH . 'uploads/' . $this->file->getRandomName(); + file_put_contents($tempFilePath, $transcriptJson); + + $newTranscriptJson = new File($tempFilePath, true); + + service('file_manager') + ->save($newTranscriptJson, $this->json_key); + } +} diff --git a/modules/Media/Entities/Video.php b/modules/Media/Entities/Video.php new file mode 100644 index 00000000..5c2d692b --- /dev/null +++ b/modules/Media/Entities/Video.php @@ -0,0 +1,16 @@ +media_path_absolute($key); + + if (! file_exists(dirname($path))) { + mkdir(dirname($path), 0777, true); + } + + if (! file_exists(dirname($path) . '/index.html')) { + touch(dirname($path) . '/index.html'); + } + + // copy to media folder, overwrite file if already existing + $isCopySuccessful = copy($file->getRealPath(), $path); + + if (! $isCopySuccessful) { + throw new Exception("Could not save file {$key} to {$path}"); + } + + // delete temporary file after copy + unlink($file->getRealPath()); + + return $key; + } + + #[Override] + public function delete(string $key): bool + { + helper('media'); + + return @unlink($this->media_path_absolute($key)); + } + + #[Override] + public function getUrl(string $key): string + { + return media_url($this->config->root . '/' . $key); + } + + #[Override] + public function rename(string $oldKey, string $newKey): bool + { + helper('media'); + + return rename($this->media_path_absolute($oldKey), $this->media_path_absolute($newKey)); + } + + #[Override] + public function getFileContents(string $key): string|false + { + helper('media'); + + return file_get_contents($this->media_path_absolute($key)); + } + + #[Override] + public function getFileInput(string $key): string + { + helper('media'); + + return $this->media_path_absolute($key); + } + + #[Override] + public function deletePodcastImageSizes(string $podcastHandle): bool + { + foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) { + $this->deleteAll("podcasts/{$podcastHandle}", "*_*{$ext}"); + } + + return true; + } + + #[Override] + public function deletePersonImagesSizes(): bool + { + foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) { + $this->deleteAll('persons', "*_*{$ext}"); + } + + return true; + } + + #[Override] + public function deleteAll(string $prefix, string $pattern = '*'): bool + { + helper('media'); + + // delete all in folder? + if ($pattern === '*') { + helper('filesystem'); + + return delete_files($this->media_path_absolute($prefix), true); + } + + $prefix = rtrim($prefix, '/') . '/'; + + $imagePaths = glob($this->media_path_absolute($prefix . $pattern)); + + if (! $imagePaths) { + return true; + } + + foreach ($imagePaths as $imagePath) { + @unlink($imagePath); + } + + return true; + } + + #[Override] + public function isHealthy(): bool + { + helper('media'); + + return is_really_writable($this->media_path_absolute()); + } + + /** + * Prefixes the absolute storage directory to the media path of a given uri + * + * @param string|string[] $uri URI string or array of URI segments + */ + private function media_path_absolute(string | array $uri = ''): string + { + // convert segment array to string + if (is_array($uri)) { + $uri = implode('/', $uri); + } + + $uri = trim($uri, '/'); + + return config('Media')->storage . '/' . config('Media')->root . '/' . $uri; + } +} diff --git a/modules/Media/FileManagers/FileManagerInterface.php b/modules/Media/FileManagers/FileManagerInterface.php new file mode 100644 index 00000000..d711230d --- /dev/null +++ b/modules/Media/FileManagers/FileManagerInterface.php @@ -0,0 +1,30 @@ +s3 = new S3Client([ + 'version' => 'latest', + 'region' => $config->s3['region'], + 'endpoint' => $config->s3['endpoint'], + 'credentials' => new Credentials((string) $config->s3['key'], (string) $config->s3['secret']), + 'debug' => $config->s3['debug'], + 'use_path_style_endpoint' => $config->s3['pathStyleEndpoint'], + ]); + } + + #[Override] + public function save(File $file, string $key): string + { + $this->s3->putObject([ + 'Bucket' => $this->config->s3['bucket'], + 'Key' => $this->prefixKey($key), + 'SourceFile' => $file, + 'ContentType' => $file->getMimeType(), + 'CacheControl' => 'max-age=' . YEAR, + 'ACL' => 'public-read', + ]); + + // delete file after storage in s3 + unlink($file->getRealPath()); + + return $key; + } + + #[Override] + public function delete(string $key): bool + { + try { + $this->s3->deleteObject([ + 'Bucket' => $this->config->s3['bucket'], + 'Key' => $this->prefixKey($key), + ]); + } catch (Exception) { + return false; + } + + return true; + } + + #[Override] + public function getUrl(string $key): string + { + return media_url($this->prefixKey($key)); + } + + #[Override] + public function rename(string $oldKey, string $newKey): bool + { + try { + // copy old object with new key + $this->s3->copyObject([ + 'Bucket' => $this->config->s3['bucket'], + 'CopySource' => $this->config->s3['bucket'] . '/' . $this->prefixKey($oldKey), + 'Key' => $this->prefixKey($newKey), + 'ACL' => 'public-read', + ]); + } catch (Exception) { + return false; + } + + // delete old object + return $this->delete($oldKey); + } + + #[Override] + public function getFileContents(string $key): string|false + { + try { + $result = $this->s3->getObject([ + 'Bucket' => $this->config->s3['bucket'], + 'Key' => $this->prefixKey($key), + ]); + } catch (Exception) { + return false; + } + + return (string) $result->get('Body'); + } + + #[Override] + public function getFileInput(string $key): string + { + return $this->getUrl($key); + } + + #[Override] + public function deletePodcastImageSizes(string $podcastHandle): bool + { + foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) { + $this->deleteAll('podcasts/' . $podcastHandle, "*_*{$ext}"); + } + + return true; + } + + #[Override] + public function deletePersonImagesSizes(): bool + { + foreach (['jpg', 'jpeg', 'png', 'webp'] as $ext) { + $this->deleteAll('persons', "*_*{$ext}"); + } + + return true; + } + + #[Override] + public function deleteAll(string $prefix, ?string $pattern = '*'): bool + { + $prefix = rtrim($this->prefixKey($prefix), '/') . '/'; // make sure that there is a trailing slash + $pattern = $prefix . $pattern; + + $results = $this->s3->getPaginator('ListObjectsV2', [ + 'Bucket' => $this->config->s3['bucket'], + 'prefix' => $prefix, + ]); + + $objectsToDelete = []; + foreach ($results as $result) { + if ($result['Contents'] === null) { + continue; + } + + foreach ($result['Contents'] as $object) { + if (fnmatch($pattern, $object['Key'])) { + $objectsToDelete[] = [ + 'Key' => $object['Key'], + ]; + } + } + } + + if ($objectsToDelete === []) { + return true; + } + + try { + $this->s3->deleteObjects([ + 'Bucket' => $this->config->s3['bucket'], + 'Delete' => [ + 'Objects' => $objectsToDelete, + ], + ]); + } catch (Exception) { + return false; + } + + return true; + } + + #[Override] + public function isHealthy(): bool + { + // check that bucket exists + if (! $this->s3->doesBucketExist((string) $this->config->s3['bucket'])) { + return false; + } + + try { + // ok if bucket exists and you have permission to access it + $this->s3->headBucket([ + 'Bucket' => $this->config->s3['bucket'], + ]); + } catch (Exception) { + return false; + } + + return true; + } + + private function prefixKey(string $key): string + { + if ($this->config->s3['keyPrefix'] === '') { + return $key; + } + + $keyPrefix = rtrim((string) $this->config->s3['keyPrefix']); + + return $keyPrefix . '/' . $key; + } +} diff --git a/modules/Media/Helpers/filesystem_helper.php b/modules/Media/Helpers/filesystem_helper.php new file mode 100644 index 00000000..9a6d00c8 --- /dev/null +++ b/modules/Media/Helpers/filesystem_helper.php @@ -0,0 +1,20 @@ +|string $relativePath URI string or array of URI segments + */ + function media_url(array|string $relativePath = '', ?string $scheme = null): string + { + // Convert array of segments to a string + if (is_array($relativePath)) { + $relativePath = implode('/', $relativePath); + } + + $uri = new URI(rtrim(config('Media')->baseURL, '/') . '/' . ltrim($relativePath)); + + return URI::createURIString( + $scheme ?? $uri->getScheme(), + $uri->getAuthority(), + $uri->getPath(), + $uri->getQuery(), + $uri->getFragment(), + ); + } +} diff --git a/modules/Media/Models/MediaModel.php b/modules/Media/Models/MediaModel.php new file mode 100644 index 00000000..d6b948a6 --- /dev/null +++ b/modules/Media/Models/MediaModel.php @@ -0,0 +1,187 @@ + + */ + protected $allowedFields = [ + 'id', + 'file_key', + 'file_size', + 'file_mimetype', + 'file_metadata', + 'type', + 'description', + 'language_code', + 'uploaded_by', + 'updated_by', + ]; + + /** + * clear cache before update if by any chance, the podcast name changes, so will the podcast link + * + * @var list + */ + protected $beforeUpdate = ['clearCache']; + + /** + * @var list + */ + protected $beforeDelete = ['clearCache']; + + /** + * @param ConnectionInterface|null $db DB Connection + * @param ValidationInterface|null $validation Validation + */ + public function __construct( + protected string $fileType = 'document', + ?ConnectionInterface &$db = null, + ?ValidationInterface $validation = null, + ) { + $this->returnType = match ($fileType) { + 'audio' => Audio::class, + 'video' => Video::class, + 'image' => Image::class, + 'transcript' => Transcript::class, + 'chapters' => Chapters::class, + default => Document::class, + }; + + parent::__construct($db, $validation); + } + + public function getMediaById(int $mediaId): mixed + { + $cacheName = "media#{$mediaId}"; + if (! ($found = cache($cacheName))) { + $found = $this->find($mediaId); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @param Document|Audio|Video|Image|Transcript|Chapters $media + */ + public function saveMedia(object $media): int | false + { + // save file first + $media->saveFile(); + + // insert record in database + /** @var int|false $mediaId */ + $mediaId = $this->insert($media, true); + + if (! $mediaId) { + $this->db->transRollback(); + + return false; + } + + return $mediaId; + } + + /** + * @param Document|Audio|Video|Image|Transcript|Chapters $media + */ + public function updateMedia(object $media): bool + { + // save file first + // FIXME: what if file is not set? + $media->saveFile(); + + // update record in database + return $this->update($media->id, $media); + } + + /** + * @return array + */ + public function getAllOfType(): array + { + $result = $this->where('type', $this->fileType) + ->findAll(); + $mediaClass = $this->returnType; + foreach ($result as $key => $media) { + $result[$key] = new $mediaClass($media->toArray(false, true)); + } + + return $result; + } + + /** + * @param Document|Audio|Video|Image|Transcript|Chapters $media + */ + public function deleteMedia($media): bool|BaseResult + { + if (! $media->deleteFile()) { + return false; + } + + return $this->delete($media->id); + } + + /** + * @param mixed[] $data + * + * @return mixed[] + */ + protected function clearCache(array $data): array + { + $mediaId = (is_array($data['id']) ? $data['id'][0] : $data['id']); + + cache() + ->delete("media#{$mediaId}"); + + return $data; + } +} diff --git a/modules/Media/TranscriptParser.php b/modules/Media/TranscriptParser.php new file mode 100644 index 00000000..67ebba2f --- /dev/null +++ b/modules/Media/TranscriptParser.php @@ -0,0 +1,232 @@ +transcriptContent = $content; + + return $this; + } + + /** + * Adapted from: https://stackoverflow.com/a/11659306 + * + * @return string Returns the json encoded string + */ + public function parseSrt(): string + { + if (! defined('SRT_STATE_SUBNUMBER')) { + define('SRT_STATE_SUBNUMBER', 0); + } + + if (! defined('SRT_STATE_TIME')) { + define('SRT_STATE_TIME', 1); + } + + if (! defined('SRT_STATE_TEXT')) { + define('SRT_STATE_TEXT', 2); + } + + if (! defined('SRT_STATE_BLANK')) { + define('SRT_STATE_BLANK', 3); + } + + $subs = []; + $state = SRT_STATE_SUBNUMBER; + $subNum = 0; + $subText = ''; + $subTime = ''; + + $lines = explode(PHP_EOL, $this->transcriptContent); + foreach ($lines as $line) { + switch ($state) { + case SRT_STATE_SUBNUMBER: + $subNum = trim($line); + $state = SRT_STATE_TIME; + break; + + case SRT_STATE_TIME: + $subTime = trim($line); + $state = SRT_STATE_TEXT; + break; + + case SRT_STATE_TEXT: + if (trim($line) === '') { + $sub = new stdClass(); + $sub->number = (int) $subNum; + [$startTime, $endTime] = explode(' --> ', $subTime); + $sub->startTime = $this->getSecondsFromTimeString($startTime); + $sub->endTime = $this->getSecondsFromTimeString($endTime); + $sub->text = trim($subText); + $subText = ''; + $state = SRT_STATE_SUBNUMBER; + $subs[] = $sub; + } elseif ($subText !== '') { + $subText .= PHP_EOL . $line; + } else { + $subText .= $line; + } + + break; + } + } + + if ($state === SRT_STATE_TEXT) { + // if file was missing the trailing newlines, we'll be in this + // state here. Append the last read text and add the last sub. + // @phpstan-ignore-next-line + $sub->text = $subText; + // @phpstan-ignore-next-line + $subs[] = $sub; + } + + $jsonString = json_encode($subs, JSON_PRETTY_PRINT); + + if (! $jsonString) { + throw new Exception('Failed to parse SRT to JSON.'); + } + + return $jsonString; + } + + public function parseVtt(): string + { + if (! defined('VTT_STATE_HEADER')) { + define('VTT_STATE_HEADER', 0); + } + + if (! defined('VTT_STATE_BLANK')) { + define('VTT_STATE_BLANK', 1); + } + + if (! defined('VTT_STATE_TIME')) { + define('VTT_STATE_TIME', 2); + } + + if (! defined('VTT_STATE_TEXT')) { + define('VTT_STATE_TEXT', 3); + } + + $subs = []; + $state = VTT_STATE_HEADER; + $subNum = 0; + $subText = ''; + $subTime = ''; + + $lines = explode(PHP_EOL, $this->transcriptContent); + // add a newline as last item, if it isn't already a newline + if (array_last($lines) !== '') { + $lines[] = PHP_EOL; + } + + foreach ($lines as $line) { + switch ($state) { + case VTT_STATE_HEADER: + $state = VTT_STATE_BLANK; + break; + + case VTT_STATE_BLANK: + $speakercount = 0; + $state = VTT_STATE_TIME; + break; + + case VTT_STATE_TIME: + $subTime = trim($line); + $state = VTT_STATE_TEXT; + break; + + case VTT_STATE_TEXT: + if (trim($line) === '') { + $state = VTT_STATE_TIME; + // @phpstan-ignore-next-line + } elseif ($subText !== '') { + $subText .= PHP_EOL . $line; + } else { + /** VTT includes a lot of information on the spoken line + * An example may look like this: + * So this is it + * We need to break this down into it's components, namely: + * 1. The actual words for the caption + * 2. Who is speaking + * 3. Any styling cues encoded in the VTT (which we dump) + * More information: https://www.w3.org/TR/webvtt1/ + * + * If there is more than one speaker in a cue, we also need + * to handle this, to repeat the start and end times for + * the second cue. + * */ + + $vtt_speaker_pattern = '/^<.*>/U'; + $removethese = ['', '<', '>']; + preg_match($vtt_speaker_pattern, $line, $matches); + if (isset($matches[0])) { + $subVoiceCue = str_replace($removethese, '', $matches[0]); + $subSpeaker = substr($subVoiceCue, strpos($subVoiceCue, ' ')); + } else { + $subSpeaker = ''; + } + + $subText .= preg_replace($vtt_speaker_pattern, '', $line); + $sub = new stdClass(); + $sub->number = $subNum; + [$startTime, $endTime] = explode(' --> ', $subTime); + $sub->startTime = $this->getSecondsFromVTTTimeString($startTime); + $sub->endTime = $this->getSecondsFromVTTTimeString($endTime); + $sub->text = trim($subText); + if ($subSpeaker !== '') { + $sub->speaker = trim($subSpeaker); + } + + $subText = ''; + $subs[] = $sub; + ++$subNum; + } + + break; + } + } + + $jsonString = json_encode($subs, JSON_PRETTY_PRINT); + + if (! $jsonString) { + throw new Exception('Failed to parse VTT to JSON.'); + } + + return $jsonString; + } + + private function getSecondsFromTimeString(string $timeString): float + { + $timeString = explode(',', $timeString); + return (strtotime($timeString[0]) - strtotime('TODAY')) + (float) "0.{$timeString[1]}"; + } + + private function getSecondsFromVTTTimeString(string $timeString): float + { + $timeString = explode('.', $timeString); + if (substr_count($timeString[0], ':') === 1) { + // add hours if only MM:SS.mmm format + $timeString[0] = '00:' . $timeString[0]; + } + + return (strtotime($timeString[0]) - strtotime('TODAY')) + (float) "0.{$timeString[1]}"; + } +} diff --git a/modules/MediaClipper/Commands/Generate.php b/modules/MediaClipper/Commands/Generate.php new file mode 100644 index 00000000..656349ac --- /dev/null +++ b/modules/MediaClipper/Commands/Generate.php @@ -0,0 +1,101 @@ +getRunningVideoClipsCount(); + if ($runningVideoClips >= config('Admin')->videoClipWorkers) { + return; + } + + // get all clips that haven't been processed yet + $scheduledClips = new ClipModel() + ->getScheduledVideoClips(); + + if ($scheduledClips === []) { + return; + } + + $data = []; + foreach ($scheduledClips as $scheduledClip) { + $data[] = [ + 'id' => $scheduledClip->id, + 'status' => 'pending', + ]; + } + + new ClipModel() + ->updateBatch($data, 'id'); + + // Loop through clips to generate them + foreach ($scheduledClips as $scheduledClip) { + try { + // set clip to pending + new ClipModel() + ->update($scheduledClip->id, [ + 'status' => 'running', + 'job_started_at' => Time::now(), + ]); + $clipper = new VideoClipper( + $scheduledClip->episode, + $scheduledClip->start_time, + $scheduledClip->end_time, + $scheduledClip->format, + $scheduledClip->theme['name'], + ); + $exitCode = $clipper->generate(); + + $clipModel = new ClipModel(); + if ($exitCode === 0) { + // success, video was generated + $scheduledClip->setMedia(new File($clipper->videoClipOutput), $clipper->videoClipFileKey); + $clipModel->update($scheduledClip->id, [ + 'media_id' => $scheduledClip->media_id, + 'status' => 'passed', + 'logs' => $clipper->logs, + 'job_ended_at' => Time::now(), + ]); + } else { + // error + $clipModel->update($scheduledClip->id, [ + 'status' => 'failed', + 'logs' => $clipper->logs, + 'job_ended_at' => Time::now(), + ]); + } + + $clipModel->clearVideoClipCache($scheduledClip->id); + } catch (Exception $exception) { + new ClipModel() + ->update($scheduledClip->id, [ + 'status' => 'failed', + 'logs' => $exception, + 'job_ended_at' => Time::now(), + ]); + } + } + } +} diff --git a/modules/MediaClipper/Config/MediaClipper.php b/modules/MediaClipper/Config/MediaClipper.php new file mode 100644 index 00000000..933ed886 --- /dev/null +++ b/modules/MediaClipper/Config/MediaClipper.php @@ -0,0 +1,346 @@ +>> + */ + public array $formats = [ + 'landscape' => [ + 'width' => 1920, + 'height' => 1080, + 'cover' => [ + 'width' => 480, + 'height' => 480, + 'radius' => 24, + 'x' => 150, + 'y' => 120, + ], + 'quotes' => [ + 'width' => 192, + 'height' => 192, + 'x' => 810, + 'y' => 210, + ], + 'podcastTitle' => [ + 'fontsize' => 20, + 'x' => 150, + 'y' => 620, + 'lineWidth' => 510, + ], + 'episodeTitle' => [ + 'fontsize' => 32, + 'x' => 150, + 'y' => 660, + 'lines' => 3, + 'lineWidth' => 510, + 'lineHeight' => 1.5, + ], + 'episodeNumbering' => [ + 'fontsize' => 18, + 'paddingX' => 10, + 'paddingY' => 5, + 'marginRight' => 10, + ], + 'timestamp' => [ + 'fontsize' => 32, + 'padding' => 10, + 'x' => 1620, + 'y' => 985, + ], + 'watermark' => [ + 'width' => 90, + 'height' => 72, + 'x' => 140, + 'y' => 960, + ], + 'progressbar' => [ + 'height' => 10, + ], + 'soundwaves' => [ + 'width' => 192, + 'height' => 108, + 'rescaleWidth' => 1920, + 'rescaleHeight' => 540, + 'x' => 0, + 'y' => 810, + 'mask' => ROOTPATH . 'modules/MediaClipper/Resources/soundwaves-mask-landscape.png', + ], + 'subtitles' => [ + 'fontsize' => 18, + 'marginL' => 180, + 'marginR' => 20, + 'marginV' => 85, + ], + ], + 'portrait' => [ + 'width' => 1080, + 'height' => 1920, + 'cover' => [ + 'width' => 280, + 'height' => 280, + 'radius' => 16, + 'x' => 50, + 'y' => 50, + ], + 'quotes' => [ + 'width' => 256, + 'height' => 256, + 'x' => 40, + 'y' => 520, + ], + 'podcastTitle' => [ + 'fontsize' => 32, + 'x' => 360, + 'y' => 55, + 'lineWidth' => 670, + ], + 'episodeTitle' => [ + 'fontsize' => 42, + 'x' => 360, + 'y' => 110, + 'lines' => 3, + 'lineWidth' => 670, + 'lineHeight' => 1.5, + ], + 'episodeNumbering' => [ + 'fontsize' => 28, + 'paddingX' => 10, + 'paddingY' => 10, + 'marginRight' => 10, + ], + 'timestamp' => [ + 'fontsize' => 48, + 'padding' => 14, + 'x' => 734, + 'y' => 1800, + ], + 'watermark' => [ + 'width' => 120, + 'height' => 96, + 'x' => 130, + 'y' => 1770, + ], + 'progressbar' => [ + 'height' => 10, + ], + 'soundwaves' => [ + 'width' => 54, + 'height' => 96, + 'rescaleWidth' => 1080, + 'rescaleHeight' => 1920, + 'x' => 0, + 'y' => 960, + 'mask' => ROOTPATH . 'modules/MediaClipper/Resources/soundwaves-mask-portrait.png', + ], + 'subtitles' => [ + 'fontsize' => 16, + 'marginL' => 40, + 'marginR' => 25, + 'marginV' => 97, + ], + ], + 'squared' => [ + 'width' => 1200, + 'height' => 1200, + 'cover' => [ + 'width' => 200, + 'height' => 200, + 'radius' => 16, + 'x' => 40, + 'y' => 40, + ], + 'quotes' => [ + 'width' => 200, + 'height' => 200, + 'x' => 85, + 'y' => 320, + ], + 'podcastTitle' => [ + 'fontsize' => 28, + 'x' => 260, + 'y' => 50, + 'lines' => 1, + 'lineWidth' => 800, + ], + 'episodeTitle' => [ + 'fontsize' => 36, + 'x' => 260, + 'y' => 90, + 'lines' => 2, + 'lineWidth' => 850, + 'lineHeight' => 1.5, + ], + 'episodeNumbering' => [ + 'fontsize' => 24, + 'paddingX' => 10, + 'paddingY' => 5, + 'marginRight' => 10, + ], + 'timestamp' => [ + 'fontsize' => 48, + 'padding' => 10, + 'x' => 855, + 'y' => 1070, + ], + 'watermark' => [ + 'width' => 120, + 'height' => 96, + 'x' => 130, + 'y' => 1040, + ], + 'progressbar' => [ + 'height' => 10, + ], + 'soundwaves' => [ + 'width' => 60, + 'height' => 60, + 'rescaleWidth' => 1200, + 'rescaleHeight' => 1200, + 'x' => 0, + 'y' => 600, + 'mask' => ROOTPATH . 'modules/MediaClipper/Resources/soundwaves-mask-squared.png', + ], + 'subtitles' => [ + 'fontsize' => 20, + 'marginL' => 60, + 'marginR' => 20, + 'marginV' => 98, + ], + ], + ]; + + /** + * @var array> + */ + public array $themes = [ + 'pine' => [ + // Previews must be a HSL colorscheme string + 'preview' => '174 100% 29%', + 'preview-background' => '172 100% 17%', + // arrays are rgb + 'background' => [0, 86, 74], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [0, 148, 134], + 'episodeNumberingBg' => [0, 61, 11], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => '009486', + 'timestampBg' => '00564A', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '00564A', + 'soundwaves' => [231, 249, 228], + ], + 'crimson' => [ + // Preview must be a HSL colorscheme string + 'preview' => '350 87% 61%', + 'preview-background' => '348 75% 40%', + // arrays are rgb + 'background' => [179, 31, 57], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [242, 70, 100], + 'episodeNumberingBg' => [152, 16, 43], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'F24664', + 'timestampBg' => 'B31F39', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => 'B31F39', + 'soundwaves' => [253, 206, 215], + ], + 'lake' => [ + // Preview must be a HSL colorscheme string + 'preview' => '194 100% 44%', + 'preview-background' => '194 100% 22%', + // arrays are rgb + 'background' => [0, 86, 113], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [0, 171, 225], + 'episodeNumberingBg' => [0, 43, 57], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => '00ABE1', + 'timestampBg' => '005671', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '005671', + 'soundwaves' => [214, 245, 255], + ], + 'amber' => [ + // Preview must be a HSL colorscheme string + 'preview' => '17 100% 57%', + 'preview-background' => '17 100% 35%', + // arrays are rgb + 'background' => [177, 50, 0], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [255, 96, 34], + 'episodeNumberingBg' => [121, 34, 0], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'FF6022', + 'timestampBg' => 'B13200', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => 'B13200', + 'soundwaves' => [255, 213, 197], + ], + 'jacaranda' => [ + // Preview must be a HSL colorscheme string + 'preview' => '254 72% 52%', + 'preview-background' => '254 73% 30%', + // arrays are rgb + 'background' => [47, 21, 132], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [86, 45, 221], + 'episodeNumberingBg' => [30, 14, 84], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => '562DDD', + 'timestampBg' => '2F1584', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '2F1584', + 'soundwaves' => [199, 185, 244], + ], + 'onyx' => [ + // Preview must be a HSL colorscheme string + 'preview' => '240 17% 2%', + 'preview-background' => '240 17% 2%', + // arrays are rgb + 'background' => [5, 5, 7], + 'text' => [255, 255, 255], + // subtitle hex color is BGR (Blue, Green, Red), + 'subtitles' => 'FFFFFF', + // quotes image MUST BE black + 'quotes' => [38, 38, 49], + 'episodeNumberingBg' => [0, 0, 0], + 'episodeNumberingText' => [255, 255, 255], + 'progressbar' => 'D5D5E1', + 'timestampBg' => '050507', + 'timestampText' => 'FFFFFF', + 'watermarkBg' => '050507', + 'soundwaves' => [213, 213, 225], + ], + ]; +} diff --git a/modules/MediaClipper/Resources/castopod-logo.png b/modules/MediaClipper/Resources/castopod-logo.png new file mode 100644 index 00000000..fa6544aa Binary files /dev/null and b/modules/MediaClipper/Resources/castopod-logo.png differ diff --git a/modules/MediaClipper/Resources/fonts/Inter-Regular.otf b/modules/MediaClipper/Resources/fonts/Inter-Regular.otf new file mode 100644 index 00000000..84e6a61c Binary files /dev/null and b/modules/MediaClipper/Resources/fonts/Inter-Regular.otf differ diff --git a/modules/MediaClipper/Resources/fonts/Inter-SemiBold.otf b/modules/MediaClipper/Resources/fonts/Inter-SemiBold.otf new file mode 100644 index 00000000..daf4c441 Binary files /dev/null and b/modules/MediaClipper/Resources/fonts/Inter-SemiBold.otf differ diff --git a/modules/MediaClipper/Resources/fonts/NotoSansMono-Regular.ttf b/modules/MediaClipper/Resources/fonts/NotoSansMono-Regular.ttf new file mode 100644 index 00000000..a850b21c Binary files /dev/null and b/modules/MediaClipper/Resources/fonts/NotoSansMono-Regular.ttf differ diff --git a/modules/MediaClipper/Resources/fonts/Rubik-Bold.ttf b/modules/MediaClipper/Resources/fonts/Rubik-Bold.ttf new file mode 100644 index 00000000..dd50bbe4 Binary files /dev/null and b/modules/MediaClipper/Resources/fonts/Rubik-Bold.ttf differ diff --git a/modules/MediaClipper/Resources/quotes.png b/modules/MediaClipper/Resources/quotes.png new file mode 100644 index 00000000..41f22cac Binary files /dev/null and b/modules/MediaClipper/Resources/quotes.png differ diff --git a/modules/MediaClipper/Resources/soundwaves-mask-landscape.png b/modules/MediaClipper/Resources/soundwaves-mask-landscape.png new file mode 100644 index 00000000..f705571f Binary files /dev/null and b/modules/MediaClipper/Resources/soundwaves-mask-landscape.png differ diff --git a/modules/MediaClipper/Resources/soundwaves-mask-portrait.png b/modules/MediaClipper/Resources/soundwaves-mask-portrait.png new file mode 100644 index 00000000..67a2bfb0 Binary files /dev/null and b/modules/MediaClipper/Resources/soundwaves-mask-portrait.png differ diff --git a/modules/MediaClipper/Resources/soundwaves-mask-squared.png b/modules/MediaClipper/Resources/soundwaves-mask-squared.png new file mode 100644 index 00000000..4c64e69a Binary files /dev/null and b/modules/MediaClipper/Resources/soundwaves-mask-squared.png differ diff --git a/modules/MediaClipper/VideoClipper.php b/modules/MediaClipper/VideoClipper.php new file mode 100644 index 00000000..55e320fb --- /dev/null +++ b/modules/MediaClipper/VideoClipper.php @@ -0,0 +1,815 @@ + + */ + final public const array FONTS = [ + 'episodeTitle' => 'Rubik-Bold.ttf', + 'podcastTitle' => 'Inter-Regular.otf', + 'subtitles' => 'Inter-SemiBold', + 'episodeNumbering' => 'Inter-SemiBold.otf', + 'timestamp' => 'NotoSansMono-Regular.ttf', + ]; + + public ?string $logs = null; + + public bool $error = false; + + public string $videoClipFileKey; + + public string $videoClipOutput; + + protected float $duration; + + protected string $audioInput; + + protected string $episodeCoverPath; + + protected string $soundbiteOutput; + + protected string $subtitlesClipOutput; + + protected string $videoClipBgOutput; + + protected ?string $episodeNumbering = null; + + protected string $tempFileOutput; + + /** + * @var array + */ + protected array $dimensions = []; + + /** + * @var array + */ + protected array $colors = []; + + /** + * @param 'landscape'|'portrait'|'squared' $format + * @param 'pine'|'crimson'|'lake'|'amber'|'jacaranda'|'onyx' $theme + */ + public function __construct( + protected Episode $episode, + protected float $start, + protected float $end, + protected string $format = 'landscape', + protected string $theme = 'pine', + ) { + $this->duration = $end - $start; + $this->episodeNumbering = $this->episodeNumbering($this->episode->number, $this->episode->season_number); + $this->dimensions = config('MediaClipper') + ->formats[$format]; + $this->colors = config('MediaClipper') + ->themes[$theme]; + + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + $this->audioInput = $fileManager->getFileInput($this->episode->audio->file_key); + $this->episodeCoverPath = $fileManager->getFileInput($this->episode->cover->file_key); + + // Temporary files to generate clip + $tempFile = tempnam(WRITEPATH . 'temp', "{$this->episode->slug}-{$this->start}-{$this->end}"); + + if (! $tempFile) { + throw new Exception( + 'Could not create temporary files, check for permissions on your ' . WRITEPATH . 'temp folder.', + ); + } + + $this->videoClipFileKey = "podcasts/{$this->episode->podcast->handle}/{$this->episode->slug}-clip-{$this->start}-to-{$this->end}-{$this->format}-{$this->theme}.mp4"; + + $this->tempFileOutput = $tempFile; + $this->videoClipOutput = $tempFile . '-video-clip.mp4'; + $this->soundbiteOutput = $tempFile . '-soundbite.mp3'; + $this->subtitlesClipOutput = $tempFile . '-subtitle.srt'; + $this->videoClipBgOutput = $tempFile . '-bg.png'; + } + + public function soundbite(): void + { + $soundbiteCmd = "ffmpeg -y -ss {$this->start} -t {$this->duration} -i {$this->audioInput} {$this->soundbiteOutput}"; + exec($soundbiteCmd); + } + + public function subtitlesClip(): void + { + if (! $this->episode->transcript instanceof Transcript) { + throw new Exception('Episode does not have a transcript!'); + } + + if ($this->episode->transcript->json_url) { + $this->generateSubtitlesClipFromJson($this->episode->transcript->json_key); + } else { + $subtitlesInput = $this->episode->transcript->file_url; + $subtitleClipCmd = "ffmpeg -y -i {$subtitlesInput} -ss {$this->start} -t {$this->duration} {$this->subtitlesClipOutput}"; + exec($subtitleClipCmd); + } + } + + public function generateSubtitlesClipFromJson(string $jsonFileKey): void + { + /** @var FileManagerInterface $fileManager */ + $fileManager = service('file_manager'); + + $jsonTranscriptString = (string) $fileManager->getFileContents($jsonFileKey); + if ($jsonTranscriptString === '') { + throw new Exception('Cannot get transcript json contents.'); + } + + $jsonTranscript = json_decode($jsonTranscriptString, true); + if ($jsonTranscript === null) { + throw new Exception('Transcript json is invalid.'); + } + + $srtClip = ''; + $segmentIndex = 1; + foreach ($jsonTranscript as $segment) { + $startTime = null; + $endTime = null; + + if ($segment['startTime'] < $this->end && $segment['endTime'] > $this->start) { + $startTime = $segment['startTime'] - $this->start; + $endTime = $segment['endTime'] - $this->start; + } + + if ($segment['startTime'] < $this->start && $this->start < $segment['endTime']) { + $startTime = 0; + } + + if ($segment['startTime'] < $this->end && $segment['endTime'] >= $this->end) { + $endTime = $this->duration; + } + + if ($startTime !== null && $endTime !== null) { + $formattedStartTime = $this->formatSeconds($startTime); + $formattedEndTime = $this->formatSeconds($endTime); + $srtClip .= << {$formattedEndTime} + {$segment['text']} + + + CODE_SAMPLE; + + ++$segmentIndex; + } + } + + // create srt clip file + file_put_contents($this->subtitlesClipOutput, $srtClip); + } + + public function formatSeconds(float $seconds): string + { + $milliseconds = str_replace('0.', '', (string) (round($seconds - floor($seconds), 3))); + + return gmdate('H:i:s', (int) floor($seconds)) . ',' . str_pad($milliseconds, 3, '0', STR_PAD_RIGHT); + } + + public function cleanTempFiles(): void + { + // delete generated video background image, soundbite & subtitlesClip + unlink($this->tempFileOutput); + unlink($this->soundbiteOutput); + unlink($this->subtitlesClipOutput); + unlink($this->videoClipBgOutput); + } + + /** + * @return int 0 for success, else error + */ + public function generate(): int + { + $this->soundbite(); + $this->subtitlesClip(); + + // check if video clip bg already exists before generating it + if (! file_exists($this->videoClipBgOutput)) { + $this->generateVideoClipBg(); + } + + $generateCmd = $this->getCmd(); + + $cmdResult = $this->cmd_exec($generateCmd); + + $this->cleanTempFiles(); + + return $cmdResult; + } + + public function getCmd(): string + { + $filters = [ + "[0:a]aformat=channel_layouts=mono,showwaves=s={$this->dimensions['soundwaves']['width']}x{$this->dimensions['soundwaves']['height']}:mode=cline:rate=10:colors=white,format=rgb24[waves]", + "[waves]scale={$this->dimensions['width']}:{$this->dimensions['height']}:flags=neighbor[resizedwaves]", + '[resizedwaves][3:v][4:v][5:v]threshold[cleanwaves]', + '[cleanwaves][2:v]alphamerge[waves_t]', + '[4:v][waves_t]overlay=x=0:y=0:shortest=1[waves_t2]', + '[waves_t2]split[m][a]', + '[m][a]alphamerge[waves_t3]', + "[waves_t3]scale={$this->dimensions['soundwaves']['rescaleWidth']}:{$this->dimensions['soundwaves']['rescaleHeight']},lutrgb=r='if(gt(val,100),{$this->colors['soundwaves'][0]},val)':g='if(gt(val,100),{$this->colors['soundwaves'][1]},val)':b='if(gt(val,100),{$this->colors['soundwaves'][2]},val)'[waves_final]", + "[1:v][waves_final]overlay=x={$this->dimensions['soundwaves']['x']}:y={$this->dimensions['soundwaves']['y']}:shortest=1,drawtext=fontfile=" . $this->getFont( + 'timestamp', + ) . ":text='%{pts\:gmtime\:{$this->start}\:%H\\\\\\\\\\:%M\\\\\\\\\\:%S\}':x={$this->dimensions['timestamp']['x']}:y={$this->dimensions['timestamp']['y']}:fontsize={$this->dimensions['timestamp']['fontsize']}:fontcolor=0x{$this->colors['timestampText']}:box=1:boxcolor=0x{$this->colors['timestampBg']}:boxborderw={$this->dimensions['timestamp']['padding']}[v3]", + "color=c=0x{$this->colors['progressbar']}:s={$this->dimensions['width']}x{$this->dimensions['progressbar']['height']}[progressbar]", + "[v3][progressbar]overlay=-w+(w/{$this->duration})*t:0:shortest=1:format=rgb,subtitles={$this->subtitlesClipOutput}:fontsdir=" . config( + 'MediaClipper', + )->fontsFolder . ":force_style='Fontname=" . self::FONTS['subtitles'] . ",Alignment=5,Fontsize={$this->dimensions['subtitles']['fontsize']},PrimaryColour=&H{$this->colors['subtitles']}&,BorderStyle=1,Outline=0,Shadow=0,MarginL={$this->dimensions['subtitles']['marginL']},MarginR={$this->dimensions['subtitles']['marginR']},MarginV={$this->dimensions['subtitles']['marginV']}'[outv]", + "[6:v]scale={$this->dimensions['watermark']['width']}:{$this->dimensions['watermark']['height']}[watermark]", + "color=0x{$this->colors['watermarkBg']}:{$this->dimensions['watermark']['width']}x{$this->dimensions['watermark']['height']}[over]", + '[over][watermark]overlay=x=0:y=0:shortest=1[watermark_box]', + "[outv][watermark_box]overlay=x={$this->dimensions['watermark']['x']}:y={$this->dimensions['watermark']['y']}:shortest=1[watermarked]", + '[watermarked]scale=w=-1:h=-1:out_color_matrix=bt709[outfinal]', + ]; + + $watermark = config('MediaClipper') + ->watermark; + + $videoClipCmd = [ + 'ffmpeg -y', + "-i {$this->soundbiteOutput}", + "-loop 1 -framerate 30 -i {$this->videoClipBgOutput}", + "-loop 1 -framerate 30 -i {$this->dimensions['soundwaves']['mask']}", + "-f lavfi -i color=gray:{$this->dimensions['width']}x{$this->dimensions['height']}", + "-f lavfi -i color=black:{$this->dimensions['width']}x{$this->dimensions['height']}", + "-f lavfi -i color=white:{$this->dimensions['width']}x{$this->dimensions['height']}", + "-loop 1 -framerate 1 -i {$watermark}", + '-filter_complex "' . implode(';', $filters) . '"', + '-t ' . $this->duration, + '-map "[outfinal]"', + '-map 0:a', + '-acodec aac', + '-vcodec libx264 -pix_fmt yuv420p', + "{$this->videoClipOutput}", + ]; + + return implode(' ', $videoClipCmd); + } + + private function episodeNumbering(?int $episodeNumber = null, ?int $seasonNumber = null): ?string + { + if (! $episodeNumber && ! $seasonNumber) { + return null; + } + + $transKey = ''; + $args = []; + if ($episodeNumber !== null) { + $args['episodeNumber'] = sprintf('%02d', $episodeNumber); + } + + if ($seasonNumber !== null) { + $args['seasonNumber'] = sprintf('%02d', $seasonNumber); + } + + if ($episodeNumber !== null && $seasonNumber !== null) { + $transKey = 'Episode.season_episode'; + } elseif ($episodeNumber !== null && $seasonNumber === null) { + $transKey = 'Episode.number'; + } elseif ($episodeNumber === null && $seasonNumber !== null) { + $transKey = 'Episode.season'; + } + + return lang($transKey . '_abbr', $args); + } + + private function generateVideoClipBg(): bool + { + $background = $this->generateBackground($this->dimensions['width'], $this->dimensions['height']); + + if (! $background instanceof GdImage) { + return false; + } + + $episodeCover = $this->createCoverImage(); + if (! $episodeCover) { + return false; + } + + $scaledEpisodeCover = $this->scaleImage( + $episodeCover, + $this->dimensions['cover']['width'], + $this->dimensions['cover']['height'], + ); + + if (! $scaledEpisodeCover) { + return false; + } + + $roundedEpisodeCover = $this->roundCorners($scaledEpisodeCover, $this->dimensions['cover']['radius']); + + if (! $roundedEpisodeCover) { + return false; + } + + $isOverlaid = $this->overlayImages( + $background, + $roundedEpisodeCover, + $this->dimensions['cover']['x'], + $this->dimensions['cover']['y'], + $this->dimensions['cover']['width'], + $this->dimensions['cover']['height'], + ); + + if (! $isOverlaid) { + return false; + } + + $this->addParagraphToImage( + $background, + $this->dimensions['podcastTitle']['x'], + $this->dimensions['podcastTitle']['y'], + $this->episode->podcast->title, + $this->getFont('podcastTitle'), + $this->dimensions['podcastTitle']['fontsize'], + $this->dimensions['podcastTitle']['lineWidth'], + $this->dimensions['podcastTitle']['lines'] ?? 1, + $this->dimensions['podcastTitle']['lineHeight'] ?? 1, + ); + + $episodeNumberingWidth = 0; + if ($this->episodeNumbering) { + $episodeTitleBox = $this->calculateTextBox( + $this->dimensions['episodeTitle']['fontsize'], + 0, + $this->getFont('episodeTitle'), + $this->episode->title, + ); + $episodeNumberingBox = $this->calculateTextBox( + $this->dimensions['episodeNumbering']['fontsize'], + 0, + $this->getFont('episodeNumbering'), + $this->episodeNumbering, + ); + if (! $episodeTitleBox || ! $episodeNumberingBox) { + return false; + } + + $episodeTitleCenter = (int) ($episodeTitleBox['height'] / 2); + $episodeNumberingCenter = (int) (($episodeNumberingBox['height'] + ($this->dimensions['episodeNumbering']['paddingY'] * 2)) / 2); + $episodeNumberingWidth = $episodeNumberingBox['width'] + ($this->dimensions['episodeNumbering']['paddingX'] * 2); + + $this->addTextWithBox( + $background, + $this->dimensions['episodeTitle']['x'], + $this->dimensions['episodeTitle']['y'] + $episodeTitleCenter - $episodeNumberingCenter, + $this->episodeNumbering, + $this->getFont('episodeNumbering'), + $this->dimensions['episodeNumbering']['fontsize'], + $this->colors['episodeNumberingText'], + $this->colors['episodeNumberingBg'], + $this->dimensions['episodeNumbering']['paddingX'], + $this->dimensions['episodeNumbering']['paddingY'], + ); + } + + $this->addParagraphToImage( + $background, + $this->dimensions['episodeTitle']['x'], + $this->dimensions['episodeTitle']['y'], + $this->episode->title, + $this->getFont('episodeTitle'), + $this->dimensions['episodeTitle']['fontsize'], + $this->dimensions['episodeTitle']['lineWidth'], + $this->dimensions['episodeTitle']['lines'], + $this->dimensions['episodeTitle']['lineHeight'] ?? 1, + $episodeNumberingWidth + ($episodeNumberingWidth === 0 ? 0 : $this->dimensions['episodeNumbering']['marginRight']), + ); + + // Add quotes for subtitles + $quotes = imagecreatefrompng(config('MediaClipper')->quotesImage); + + if (! $quotes) { + return false; + } + + $cleanedQuotes = $this->cleanTransparency($quotes); + + if (! $cleanedQuotes) { + return false; + } + + imagefilter($cleanedQuotes, IMG_FILTER_CONTRAST, 255); + imagefilter($cleanedQuotes, IMG_FILTER_COLORIZE, ...$this->colors['quotes']); + + $scaledQuotes = $this->scaleImage( + $cleanedQuotes, + $this->dimensions['quotes']['width'], + $this->dimensions['quotes']['height'], + ); + + if (! $scaledQuotes) { + return false; + } + + imagesavealpha($scaledQuotes, true); + $this->overlayImages( + $background, + $scaledQuotes, + $this->dimensions['quotes']['x'], + $this->dimensions['quotes']['y'], + $this->dimensions['quotes']['width'], + $this->dimensions['quotes']['height'], + ); + + // Save Image + imagepng($background, $this->videoClipBgOutput); + + return true; + } + + /** + * @return int 0 (success), 1 - 2 - 254 - 255 (error) + */ + private function cmd_exec(string $cmd): int + { + $outFile = tempnam(WRITEPATH . 'logs', 'cmd-out-'); + + if (! $outFile) { + return 254; + } + + $descriptorSpec = [ + 0 => ['pipe', 'r'], + 1 => ['pipe', 'w'], + 2 => ['file', $outFile, 'w'], + // FFmpeg outputs to stderr by default + ]; + $proc = proc_open($cmd, $descriptorSpec, $pipes); + + if (! is_resource($proc)) { + return 255; + } + + fclose($pipes[0]); //Don't really want to give any input + + $exit = proc_close($proc); + + $this->logs = (string) file_get_contents($outFile); + + // remove temporary files + unlink($outFile); + + return $exit; + } + + private function getFont(string $name): string + { + return config('MediaClipper')->fontsFolder . self::FONTS[$name]; + } + + private function generateBackground(int $width, int $height): ?GdImage + { + $background = imagecreatetruecolor($width, $height); + + if ($background === false) { + return null; + } + + $coloredBackground = imagecolorallocate($background, ...$this->colors['background']); + + if ($coloredBackground === false) { + return null; + } + + imagefill($background, 0, 0, $coloredBackground); + + return $background; + } + + private function createCoverImage(): GdImage | false + { + return match ($this->episode->cover->file_mimetype) { + 'image/jpeg' => imagecreatefromjpeg($this->episodeCoverPath), + 'image/png' => imagecreatefrompng($this->episodeCoverPath), + default => imagecreate(1400, 1400), + }; + } + + private function scaleImage(GdImage $image, int $width, int $height): GdImage | false + { + return imagescale($image, $width, $height); + } + + /** + * Copied and adapted from https://stackoverflow.com/a/52626818 + */ + private function roundCorners(GdImage $source, int $radius): GdImage | false + { + $ws = imagesx($source); + $hs = imagesy($source); + + $corner = $radius + 2; + $s = $corner * 2; + + $src = imagecreatetruecolor($s, $s); + if ($src === false) { + return false; + } + + imagecopy($src, $source, 0, 0, 0, 0, $corner, $corner); + imagecopy($src, $source, $corner, 0, $ws - $corner, 0, $corner, $corner); + imagecopy($src, $source, $corner, $corner, $ws - $corner, $hs - $corner, $corner, $corner); + imagecopy($src, $source, 0, $corner, 0, $hs - $corner, $corner, $corner); + + $q = 8; # change this if you want + $radius *= $q; + + # find unique color + do { + $r = random_int(0, 255); + $g = random_int(0, 255); + $b = random_int(0, 255); + } while (imagecolorexact($src, $r, $g, $b) < 0); + + $ns = $s * $q; + + $img = imagecreatetruecolor($ns, $ns); + if ($img === false) { + return false; + } + + $alphacolor = imagecolorallocatealpha($img, $r, $g, $b, 127); + + if ($alphacolor === false) { + return false; + } + + imagealphablending($img, false); + imagefilledrectangle($img, 0, 0, $ns, $ns, $alphacolor); + + imagefill($img, 0, 0, $alphacolor); + imagecopyresampled($img, $src, 0, 0, 0, 0, $ns, $ns, $s, $s); + + imagearc($img, $radius - 1, $radius - 1, $radius * 2, $radius * 2, 180, 270, $alphacolor); + imagefilltoborder($img, 0, 0, $alphacolor, $alphacolor); + imagearc($img, $ns - $radius, $radius - 1, $radius * 2, $radius * 2, 270, 0, $alphacolor); + imagefilltoborder($img, $ns - 1, 0, $alphacolor, $alphacolor); + imagearc($img, $radius - 1, $ns - $radius, $radius * 2, $radius * 2, 90, 180, $alphacolor); + imagefilltoborder($img, 0, $ns - 1, $alphacolor, $alphacolor); + imagearc($img, $ns - $radius, $ns - $radius, $radius * 2, $radius * 2, 0, 90, $alphacolor); + imagefilltoborder($img, $ns - 1, $ns - 1, $alphacolor, $alphacolor); + imagealphablending($img, true); + imagecolortransparent($img, $alphacolor); + + # resize image down + $dest = imagecreatetruecolor($s, $s); + if ($dest === false) { + return false; + } + + imagealphablending($dest, false); + imagefilledrectangle($dest, 0, 0, $s, $s, $alphacolor); + imagecopyresampled($dest, $img, 0, 0, 0, 0, $s, $s, $ns, $ns); + + # output image + imagealphablending($source, false); + imagecopy($source, $dest, 0, 0, 0, 0, $corner, $corner); + imagecopy($source, $dest, $ws - $corner, 0, $corner, 0, $corner, $corner); + imagecopy($source, $dest, $ws - $corner, $hs - $corner, $corner, $corner, $corner, $corner); + imagecopy($source, $dest, 0, $hs - $corner, 0, $corner, $corner, $corner); + imagealphablending($source, true); + + return $source; + } + + private function overlayImages( + GdImage $background, + GdImage $foreground, + int $x, + int $y, + int $width, + int $height, + ): bool { + return imagecopy($background, $foreground, $x, $y, 0, 0, $width, $height); + } + + private function addParagraphToImage( + GdImage $image, + int $x, + int $y, + string $text, + string $fontPath, + int $fontsize, + int $lineWidth, + int $numberOfLines = 1, + float $lineHeight = 1, + int $paragraphIndent = 0, + ): bool { + // Allocate A Color For The Text + $textColor = imagecolorallocate($image, ...$this->colors['text']); + + if ($textColor === false) { + return false; + } + + $lines = $this->textToParagraph($text, $fontPath, $fontsize, $lineWidth, $numberOfLines, $paragraphIndent); + if (! $lines) { + return false; + } + + $leading = (int) ($fontsize * $lineHeight); + foreach ($lines as $i => $line) { + // Print line On Image + imagettftext( + $image, + $fontsize, + 0, + $x + ($paragraphIndent * ($i === 0 ? 1 : 0)), + $y + $fontsize + ($leading * $i), + $textColor, + $fontPath, + $line, + ); + } + + return true; + } + + /** + * Adapted from: https://www.php.net/manual/fr/function.imagettfbbox.php#105593 + * + * @return array|false + */ + private function calculateTextBox(int $fontSize, int $fontAngle, string $fontFile, string $text): array|bool + { + /************ + simple function that calculates the *exact* bounding box (single pixel precision). + The function returns an associative array with these keys: + left, top: coordinates you will pass to imagettftext + width, height: dimension of the image you have to create + *************/ + $bbox = imagettfbbox($fontSize, $fontAngle, $fontFile, $text); + if (! $bbox) { + return false; + } + + $minX = min([$bbox[0], $bbox[2], $bbox[4], $bbox[6]]); + $maxX = max([$bbox[0], $bbox[2], $bbox[4], $bbox[6]]); + $minY = min([$bbox[1], $bbox[3], $bbox[5], $bbox[7]]); + $maxY = max([$bbox[1], $bbox[3], $bbox[5], $bbox[7]]); + + return [ + 'left' => abs($minX) - 1, + 'top' => abs($minY), + 'width' => $maxX - $minX, + 'height' => $maxY - $minY, + 'box' => $bbox, + ]; + } + + /** + * @param int[] $boxTextColor + * @param int[] $boxBgColor + */ + private function addTextWithBox( + GdImage $image, + int $x, + int $y, + string $text, + string $fontPath, + int $fontsize, + array $boxTextColor, + array $boxBgColor, + int $paddingX = 0, + int $paddingY = 0, + ): bool { + // Create some colors + $textColor = imagecolorallocate($image, ...$boxTextColor); + $bgColor = imagecolorallocate($image, ...$boxBgColor); + + if ($textColor === false || $bgColor === false) { + return false; + } + + $bbox = $this->calculateTextBox($fontsize, 0, $fontPath, $text); + + if ($bbox === false) { + return false; + } + + $x1 = $x + $bbox['left'] + $paddingX; + $y1 = $y + $bbox['top'] + $paddingY; + $x2 = $x + $bbox['width'] + ($paddingX * 2); + $y2 = $y + $bbox['height'] + ($paddingY * 2); + + imagefilledrectangle($image, $x, $y, $x2, $y2, $bgColor); + imagettftext($image, $fontsize, 0, $x1, $y1, $textColor, $fontPath, $text); + + return true; + } + + /** + * This helps getting a truly transparent background for images with transparency: + * https://stackoverflow.com/a/2611911 + */ + private function cleanTransparency(GdImage $image): GdImage | false + { + $imageBg = imagecolorallocate($image, 0, 0, 0); + if ($imageBg === false) { + return false; + } + + // removing the black from the image + imagecolortransparent($image, $imageBg); + + // turning off alpha blending (to ensure alpha channel information + // is preserved, rather than removed (blending with the rest of the + // image in the form of black)) + imagealphablending($image, false); + + // turning on alpha channel information saving (to ensure the full range + // of transparency is preserved) + imagesavealpha($image, true); + + return $image; + } + + /** + * @return array|false + */ + private function textToParagraph( + string $text, + string $fontPath, + int $fontsize, + int $lineWidth, + int $numberOfLines, + int $paragraphIndent = 0, + ): array|bool { + // check length of text + $bbox = $this->calculateTextBox($fontsize, 0, $fontPath, $text); + if (! $bbox) { + return false; + } + + // return early if text width is less than line width + if ($bbox['width'] <= $lineWidth) { + return [$text]; + } + + // cut text in multiple lines based on the lineWidth property + $lines = ['']; + $length = $paragraphIndent; + $words = preg_split('~\b(?=\S)|(?=\s)~', $text); + if (! $words) { + return false; + } + + $wordCount = count($words); + $lineNumber = 0; + for ($i = 0; $i < $wordCount; ++$i) { + $word = $words[$i]; + $wordBox = $this->calculateTextBox($fontsize, 0, $fontPath, $word); + if (! $wordBox) { + return false; + } + + $wordWidth = $wordBox['width']; + + if (($wordWidth + $length) > $lineWidth) { + ++$lineNumber; + if ($lineNumber > $numberOfLines - 1) { + $lines[$numberOfLines - 1] .= '…'; + break; + } + + $lines[$lineNumber] = ''; + $length = 0; + + // If the current word is just a space, don't bother. Skip (saves a weird-looking gap in the text). + if ($word === ' ') { + continue; + } + } + + $lines[$lineNumber] .= $word; + $length += $wordWidth; + } + + return $lines; + } +} diff --git a/modules/Platforms/Config/Routes.php b/modules/Platforms/Config/Routes.php new file mode 100644 index 00000000..06284656 --- /dev/null +++ b/modules/Platforms/Config/Routes.php @@ -0,0 +1,64 @@ +addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding'); + +// Admin routes for subscriptions +$routes->group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\Platforms\Controllers', + ], + static function ($routes): void { + $routes->group('podcasts/(:num)/platforms', static function ($routes): void { + $routes->get( + '/', + 'PlatformController::list/$1/podcasting', + [ + 'as' => 'platforms-podcasting', + 'filter' => 'permission:podcast$1.manage-platforms', + ], + ); + $routes->get( + 'social', + 'PlatformController::list/$1/social', + [ + 'as' => 'platforms-social', + 'filter' => 'permission:podcast$1.manage-platforms', + ], + ); + $routes->get( + 'funding', + 'PlatformController::list/$1/funding', + [ + 'as' => 'platforms-funding', + 'filter' => 'permission:podcast$1.manage-platforms', + ], + ); + $routes->post( + 'save/(:platformType)', + 'PlatformController::updateAction/$1/$2', + [ + 'as' => 'platforms-save', + 'filter' => 'permission:podcast$1.manage-platforms', + ], + ); + $routes->get( + '(:platformType)/(:slug)/podcast-platform-remove', + 'PlatformController::removeAction/$1/$2/$3', + [ + 'as' => 'podcast-platform-remove', + 'filter' => 'permission:podcast$1.manage-platforms', + ], + ); + }); + }, +); diff --git a/modules/Platforms/Config/Services.php b/modules/Platforms/Config/Services.php new file mode 100644 index 00000000..c9912c0c --- /dev/null +++ b/modules/Platforms/Config/Services.php @@ -0,0 +1,20 @@ +{$method}(); + } + + if ( + ! ($podcast = new PodcastModel()->getPodcastById((int) $params[0])) instanceof Podcast + ) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->podcast = $podcast; + + unset($params[0]); + return $this->{$method}(...$params); + } + + public function index(): string + { + return view('podcast/platforms/dashboard'); + } + + public function list(string $platformType): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + 'platformType' => $platformType, + 'platforms' => new PlatformModel() + ->getPlatformsWithData($this->podcast->id, $platformType), + ]; + + $this->setHtmlHead(lang("Platforms.title.{$platformType}")); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + ]); + return view('podcast/platforms', $data); + } + + public function updateAction(string $platformType): RedirectResponse + { + $platformModel = new PlatformModel(); + $validation = service('validation'); + + $platformsData = []; + foreach ( + $this->request->getPost('platforms') as $platformSlug => $podcastPlatform + ) { + $podcastPlatformUrl = trim((string) $podcastPlatform['url']); + if ($podcastPlatformUrl === '') { + continue; + } + + if (! $validation->check(htmlentities($podcastPlatformUrl), 'valid_url_strict')) { + continue; + } + + $podcastPlatformAccountId = trim((string) $podcastPlatform['account_id']); + $platformsData[] = [ + 'podcast_id' => $this->podcast->id, + 'type' => $platformType, + 'slug' => $platformSlug, + 'link_url' => $podcastPlatformUrl, + 'account_id' => $podcastPlatformAccountId === '' ? null : $podcastPlatformAccountId, + 'is_visible' => array_key_exists('visible', $podcastPlatform) && + $podcastPlatform['visible'] === 'yes', + ]; + } + + $platformModel->savePlatforms($this->podcast->id, $platformType, $platformsData); + + return redirect() + ->back() + ->with('message', lang('Platforms.messages.updateSuccess')); + } + + public function removeAction(string $platformType, string $platformSlug): RedirectResponse + { + new PlatformModel() + ->removePlatform($this->podcast->id, $platformType, $platformSlug); + + return redirect() + ->back() + ->with('message', lang('Platforms.messages.removeLinkSuccess')); + } +} diff --git a/modules/Platforms/Entities/Platform.php b/modules/Platforms/Entities/Platform.php new file mode 100644 index 00000000..0f2a6710 --- /dev/null +++ b/modules/Platforms/Entities/Platform.php @@ -0,0 +1,42 @@ + + */ + protected $casts = [ + 'podcast_id' => 'int', + 'slug' => 'string', + 'type' => 'string', + 'label' => 'string', + 'link_url' => 'string', + 'account_id' => '?string', + 'is_visible' => 'boolean', + 'home_url' => 'string', + 'submit_url' => '?string', + ]; +} diff --git a/modules/Platforms/Models/PlatformModel.php b/modules/Platforms/Models/PlatformModel.php new file mode 100644 index 00000000..8ba8c89a --- /dev/null +++ b/modules/Platforms/Models/PlatformModel.php @@ -0,0 +1,179 @@ + + */ + protected $allowedFields = ['podcast_id', 'type', 'slug', 'link_url', 'account_id', 'is_visible']; + + /** + * @var class-string + */ + protected $returnType = Platform::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = false; + + /** + * @return Platform[] + */ + public function getPlatformsWithData(int $podcastId, string $platformType): array + { + $cacheName = "podcast#{$podcastId}_platforms_{$platformType}_withData"; + if (! ($found = cache($cacheName))) { + $platforms = service('platforms'); + + $found = $this->getPlatforms($podcastId, $platformType); + $platformsData = $platforms->getPlatformsByType($platformType); + + $knownSlugs = []; + foreach ($found as $podcastPlatform) { + $knownSlugs[] = $podcastPlatform->slug; + } + + foreach ($platformsData as $slug => $platform) { + if (! in_array($slug, $knownSlugs, true)) { + $found[] = new Platform([ + 'podcast_id' => $podcastId, + 'slug' => $slug, + 'type' => $platformType, + 'label' => $platform['label'], + 'home_url' => $platform['home_url'], + 'submit_url' => $platform['submit_url'], + 'link_url' => '', + 'account_id' => null, + 'is_visible' => false, + ]); + } + } + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @return Platform[] + */ + public function getPlatforms(int $podcastId, string $platformType): array + { + $cacheName = "podcast#{$podcastId}_platforms_{$platformType}"; + if (! ($found = cache($cacheName))) { + $platforms = service('platforms'); + + /** @var Platform[] $found */ + $found = $this + ->where('podcast_id', $podcastId) + ->where('type', $platformType) + ->orderBy('slug') + ->findAll(); + + foreach ($found as $platform) { + $platformData = $platforms->findPlatformBySlug($platformType, $platform->slug); + + if ($platformData === null) { + // delete platform, it does not correspond to any existing one + $this->delete($platform->id); + + continue; + } + + $platform->type = $platformType; + $platform->label = $platformData['label']; + $platform->home_url = $platformData['home_url']; + $platform->submit_url = $platformData['submit_url']; + } + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @param array> $data + * + * @return int|false Number of rows inserted or FALSE on failure + */ + public function savePlatforms(int $podcastId, string $platformType, array $data): int | false + { + $this->clearCache($podcastId); + + $platforms = service('platforms'); + + $platformsData = $platforms->getPlatformsByType($platformType); + + $this->builder() + ->whereIn('slug', array_keys($platformsData)) + ->delete(); + + if ($data === []) { + // no rows inserted + return 0; + } + + return $this->insertBatch($data); + } + + public function removePlatform(int $podcastId, string $platformType, string $platformSlug): bool | string + { + $this->clearCache($podcastId); + + return $this->builder() + ->delete([ + 'podcast_id' => $podcastId, + 'type' => $platformType, + 'slug' => $platformSlug, + ]); + } + + public function clearCache(int $podcastId): void + { + cache()->deleteMatching("podcast#{$podcastId}_platforms_*"); + + // delete localized podcast page cache + cache() + ->deleteMatching("page_podcast#{$podcastId}*"); + // delete post and episode comments pages cache + cache() + ->deleteMatching('page_post*'); + cache() + ->deleteMatching('page_episode#*'); + } +} diff --git a/modules/Platforms/Platforms.php b/modules/Platforms/Platforms.php new file mode 100644 index 00000000..13cf436c --- /dev/null +++ b/modules/Platforms/Platforms.php @@ -0,0 +1,478 @@ +> + */ + public const DATA = [ + 'podcasting' => [ + 'amazon' => [ + 'label' => 'Amazon Music', + 'home_url' => 'https://music.amazon.com/', + 'submit_url' => 'https://podcasters.amazon.com/', + ], + 'antennapod' => [ + 'label' => 'AntennaPod', + 'home_url' => 'https://antennapod.org/', + 'submit_url' => 'https://antennapod.org/documentation/podcasters-hosters/add-on-antennapod', + ], + 'anytime' => [ + 'label' => 'Anytime Podcast Player', + 'home_url' => 'https://anytimeplayer.app/', + 'submit_url' => null, + ], + 'apple' => [ + 'label' => 'Apple Podcasts', + 'home_url' => 'https://www.apple.com/itunes/podcasts/', + 'submit_url' => 'https://podcastsconnect.apple.com/my-podcasts/new-feed', + ], + 'blubrry' => [ + 'label' => 'Blubrry', + 'home_url' => 'https://www.blubrry.com/', + 'submit_url' => 'https://www.blubrry.com/addpodcast.php', + ], + 'breez' => [ + 'label' => 'Breez', + 'home_url' => 'https://breez.technology/', + 'submit_url' => null, + ], + 'castamatic' => [ + 'label' => 'Castamatic', + 'home_url' => 'https://castamatic.com/', + 'submit_url' => null, + ], + 'castbox' => [ + 'label' => 'Castbox', + 'home_url' => 'https://castbox.fm/', + 'submit_url' => 'https://helpcenter.castbox.fm/portal/kb/articles/submit-my-podcast', + ], + 'castopod' => [ + 'label' => 'Castopod', + 'home_url' => 'https://castopod.org/', + 'submit_url' => 'https://castopod.org/instances', + ], + 'castro' => [ + 'label' => 'Castro', + 'home_url' => 'http://castro.fm/', + 'submit_url' => 'https://castro.fm/support/link-to-your-podcast-in-castro', + ], + 'curiocaster' => [ + 'label' => 'CurioCaster', + 'home_url' => 'https://curiocaster.com/', + 'submit_url' => null, + ], + 'deezer' => [ + 'label' => 'Deezer', + 'home_url' => 'https://www.deezer.com/', + 'submit_url' => 'https://podcasters.deezer.com/submission', + ], + 'episodes-fm' => [ + 'label' => 'Episodes.fm', + 'home_url' => 'https://episodes.fm/', + 'submit_url' => 'https://podcastindex.org/add', + ], + 'fountain' => [ + 'label' => 'Fountain', + 'home_url' => 'https://www.fountain.fm/', + 'submit_url' => 'https://support.fountain.fm/article/56-how-to-claim-your-show-on-fountain', + ], + 'fyyd' => [ + 'label' => 'fyyd', + 'home_url' => 'https://fyyd.de/', + 'submit_url' => 'https://fyyd.de/add-feed', + ], + 'gpodder' => [ + 'label' => 'gPodder', + 'home_url' => 'https://gpodder.org/', + 'submit_url' => null, + ], + 'ivoox' => [ + 'label' => 'Ivoox', + 'home_url' => 'https://www.ivoox.com/', + 'submit_url' => null, + ], + 'listennotes' => [ + 'label' => 'ListenNotes', + 'home_url' => 'https://www.listennotes.com/', + 'submit_url' => 'https://www.listennotes.com/submit/', + ], + 'overcast' => [ + 'label' => 'Overcast', + 'home_url' => 'https://overcast.fm/', + 'submit_url' => 'https://overcast.fm/podcasterinfo', + ], + 'playerfm' => [ + 'label' => 'Player.Fm', + 'home_url' => 'https://player.fm/', + 'submit_url' => 'https://player.fm/importer/feed', + ], + 'pocketcasts' => [ + 'label' => 'Pocketcasts', + 'home_url' => 'https://www.pocketcasts.com/', + 'submit_url' => 'https://www.pocketcasts.com/submit/', + ], + 'podbean' => [ + 'label' => 'Podbean', + 'home_url' => 'https://www.podbean.com/', + 'submit_url' => 'https://www.podbean.com/site/submitPodcast', + ], + 'podcastaddict' => [ + 'label' => 'Podcast Addict', + 'home_url' => 'https://podcastaddict.com/', + 'submit_url' => 'https://podcastaddict.com/submit', + ], + 'podcastindex' => [ + 'label' => 'Podcast Index', + 'home_url' => 'https://podcastindex.org/', + 'submit_url' => 'https://podcastindex.org/add', + ], + 'podchaser' => [ + 'label' => 'Podchaser', + 'home_url' => 'https://www.podchaser.com/', + 'submit_url' => 'https://www.podchaser.com/add', + ], + 'podcloud' => [ + 'label' => 'podCloud', + 'home_url' => 'https://podcloud.fr/', + 'submit_url' => 'https://podcloud.fr/studio/podcasts/new', + ], + 'podlink' => [ + 'label' => 'pod.link', + 'home_url' => 'https://pod.link/', + 'submit_url' => null, + ], + 'podtail' => [ + 'label' => 'Podtail', + 'home_url' => 'https://podtail.com/', + 'submit_url' => 'https://podtail.com/about/faq/', + ], + 'podfriend' => [ + 'label' => 'Podfriend', + 'home_url' => 'https://www.podfriend.com/', + 'submit_url' => 'https://podcastindex.org/add', + ], + 'podverse' => [ + 'label' => 'Podverse', + 'home_url' => 'https://podverse.fm/', + 'submit_url' => 'https://docs.google.com/forms/d/e/1FAIpQLSdewKP-YrE8zGjDPrkmoJEwCxPl_gizEkmzAlTYsiWAuAk1Ng/viewform', + ], + 'radiopublic' => [ + 'label' => 'RadioPublic', + 'home_url' => 'https://radiopublic.com/', + 'submit_url' => 'https://podcasters.radiopublic.com/signup', + ], + 'spotify' => [ + 'label' => 'Spotify', + 'home_url' => 'https://www.spotify.com/', + 'submit_url' => 'https://podcasters.spotify.com/dash/submit', + ], + 'spreaker' => [ + 'label' => 'Spreaker', + 'home_url' => 'https://www.spreaker.com/', + 'submit_url' => 'https://www.spreaker.com/cms/shows/rss-import', + ], + 'tunein' => [ + 'label' => 'TuneIn', + 'home_url' => 'https://tunein.com/', + 'submit_url' => 'https://help.tunein.com/contact/add-podcast-S19TR3Sdf', + ], + 'hypercatcher' => [ + 'label' => 'HyperCatcher', + 'home_url' => 'https://hypercatcher.com/', + 'submit_url' => null, + ], + 'ivyfm' => [ + 'label' => 'Ivy.fm', + 'home_url' => 'https://ivy.fm/', + 'submit_url' => null, + ], + 'jumplink' => [ + 'label' => 'JumpLink', + 'home_url' => 'https://jump.link/', + 'submit_url' => 'https://jump.link/a/accounts/signup/', + ], + 'kasts' => [ + 'label' => 'Kasts', + 'home_url' => 'https://apps.kde.org/kasts/', + 'submit_url' => null, + ], + 'playapod' => [ + 'label' => 'Playapod', + 'home_url' => 'https://playapod.com/', + 'submit_url' => null, + ], + 'plink' => [ + 'label' => 'Plink', + 'home_url' => 'https://plinkhq.com/', + 'submit_url' => null, + ], + 'podcastchapters' => [ + 'label' => 'Podcast Chapters', + 'home_url' => 'https://chaptersapp.com/', + 'submit_url' => null, + ], + 'podcastguru' => [ + 'label' => 'Podcast Guru', + 'home_url' => 'https://podcastguru.io/', + 'submit_url' => 'https://podcastguru.io/promote-your-podcast/', + ], + 'podlp' => [ + 'label' => 'PodLP', + 'home_url' => 'https://podlp.com/', + 'submit_url' => 'https://podlp.com/submit.html', + ], + 'podnews' => [ + 'label' => 'Podnews', + 'home_url' => 'https://podnews.net/', + 'submit_url' => 'https://podnews.net/podcast/subscribe-pages', + ], + 'podstation' => [ + 'label' => 'podStation', + 'home_url' => 'https://podstation.github.io/', + 'submit_url' => null, + ], + 'sphinxchat' => [ + 'label' => 'Sphinx', + 'home_url' => 'https://sphinx.chat/', + 'submit_url' => null, + ], + 'truefans' => [ + 'label' => 'Truefans', + 'home_url' => 'https://truefans.fm/', + 'submit_url' => 'https://podcastindex.org/add', + ], + 'tsacdop' => [ + 'label' => 'Tsacdop', + 'home_url' => 'https://www.tsacdop.app/', + 'submit_url' => null, + ], + 'youtube-music' => [ + 'label' => 'YouTube Music', + 'home_url' => 'https://www.youtube.com/creators/podcasts/', + 'submit_url' => 'https://studio.youtube.com/channel/content/podcasts', + ], + ], + 'social' => [ + 'bluesky' => [ + 'label' => 'Bluesky', + 'home_url' => 'https://bsky.app/', + 'submit_url' => 'https://bsky.app/', + ], + 'discord' => [ + 'label' => 'Discord', + 'home_url' => 'https://discord.com/', + 'submit_url' => 'https://discord.com/register', + ], + 'discourse' => [ + 'label' => 'Discourse', + 'home_url' => 'https://www.discourse.org/', + 'submit_url' => null, + ], + 'facebook' => [ + 'label' => 'Facebook', + 'home_url' => 'https://www.facebook.com/', + 'submit_url' => 'https://www.facebook.com/pages/creation/', + ], + 'funkwhale' => [ + 'label' => 'Funkwhale', + 'home_url' => 'https://funkwhale.audio/', + 'submit_url' => 'https://network.funkwhale.audio/dashboards/', + ], + 'instagram' => [ + 'label' => 'Instagram', + 'home_url' => 'https://www.instagram.com/', + 'submit_url' => 'https://www.instagram.com/accounts/emailsignup/', + ], + 'linkedin' => [ + 'label' => 'LinkedIn', + 'home_url' => 'https://www.linkedin.com/', + 'submit_url' => 'https://www.linkedin.com/company/setup/new/', + ], + 'mastodon' => [ + 'label' => 'Mastodon', + 'home_url' => 'https://joinmastodon.org/', + 'submit_url' => 'https://joinmastodon.org/communities', + ], + 'matrix' => [ + 'label' => 'Matrix', + 'home_url' => 'https://matrix.org/', + 'submit_url' => 'https://matrix.org/try-matrix/', + ], + 'misskey' => [ + 'label' => 'Misskey', + 'home_url' => 'https://join.misskey.page/', + 'submit_url' => 'https://join.misskey.page/en-US/instances', + ], + 'mobilizon' => [ + 'label' => 'Mobilizon', + 'home_url' => 'https://joinmobilizon.org/', + 'submit_url' => 'https://instances.joinmobilizon.org/instances', + ], + 'peertube' => [ + 'label' => 'PeerTube', + 'home_url' => 'https://joinpeertube.org/', + 'submit_url' => 'https://joinpeertube.org/instances', + ], + 'pixelfed' => [ + 'label' => 'Pixelfed', + 'home_url' => 'https://pixelfed.org/', + 'submit_url' => 'https://beta.joinpixelfed.org/', + ], + 'pleroma' => [ + 'label' => 'Pleroma', + 'home_url' => 'https://pleroma.social/', + 'submit_url' => 'https://pleroma.social/#featured-instances', + ], + 'plume' => [ + 'label' => 'Plume', + 'home_url' => 'https://joinplu.me/', + 'submit_url' => 'https://joinplu.me/#instances', + ], + 'slack' => [ + 'label' => 'Slack', + 'home_url' => 'https://slack.com/', + 'submit_url' => 'https://slack.com/get-started#/create', + ], + 'telegram' => [ + 'label' => 'Telegram', + 'home_url' => 'https://www.telegram.org/', + 'submit_url' => null, + ], + 'threads' => [ + 'label' => 'Threads', + 'home_url' => 'https://www.threads.net/', + 'submit_url' => 'https://www.threads.net/login', + ], + 'tiktok' => [ + 'label' => 'TikTok', + 'home_url' => 'https://www.tiktok.com/', + 'submit_url' => 'https://www.tiktok.com/signup', + ], + 'twitch' => [ + 'label' => 'Twitch', + 'home_url' => 'https://www.twitch.tv/', + 'submit_url' => 'https://www.twitch.tv/signup', + ], + 'writefreely' => [ + 'label' => 'WriteFreely', + 'home_url' => 'https://writefreely.org/', + 'submit_url' => 'https://writefreely.org/instances', + ], + 'youtube' => [ + 'label' => 'YouTube', + 'home_url' => 'https://www.youtube.com/', + 'submit_url' => 'https://studio.youtube.com/', + ], + 'x' => [ + 'label' => 'Twitter / X', + 'home_url' => 'https://x.com/', + 'submit_url' => 'https://x.com/i/flow/signup', + ], + ], + 'funding' => [ + 'buymeacoffee' => [ + 'label' => 'Buy Me a Coffee', + 'home_url' => 'https://www.buymeacoffee.com/', + 'submit_url' => 'https://www.buymeacoffee.com/signup', + ], + 'paypal' => [ + 'label' => 'PayPal', + 'home_url' => 'https://www.paypal.com/', + 'submit_url' => 'https://www.paypal.com/paypalme/my/grab', + ], + 'fosspay' => [ + 'label' => 'fosspay', + 'home_url' => 'https://git.sr.ht/~sircmpwn/fosspay', + 'submit_url' => null, + ], + 'gofundme' => [ + 'label' => 'GoFundMe', + 'home_url' => 'https://www.gofundme.com/', + 'submit_url' => 'https://www.gofundme.com/sign-up', + ], + 'helloasso' => [ + 'label' => 'HelloAsso', + 'home_url' => 'https://www.helloasso.com/', + 'submit_url' => 'https://auth.helloasso.com/inscription', + ], + 'indiegogo' => [ + 'label' => 'Indiegogo', + 'home_url' => 'https://www.indiegogo.com/', + 'submit_url' => 'https://www.indiegogo.com/start-a-campaign#/', + ], + 'kickstarter' => [ + 'label' => 'Kickstarter', + 'home_url' => 'https://www.kickstarter.com/', + 'submit_url' => 'https://www.kickstarter.com/learn', + ], + 'kisskissbankbank' => [ + 'label' => 'KissKissBankBank', + 'home_url' => 'https://www.kisskissbankbank.com/', + 'submit_url' => 'https://www.kisskissbankbank.com/en/financer-mon-projet', + ], + 'kofi' => [ + 'label' => 'Ko-fi', + 'home_url' => 'https://ko-fi.com/', + 'submit_url' => 'https://ko-fi.com/account/register', + ], + 'liberapay' => [ + 'label' => 'Liberapay', + 'home_url' => 'https://liberapay.com/', + 'submit_url' => 'https://liberapay.com/sign-up', + ], + 'patreon' => [ + 'label' => 'Patreon', + 'home_url' => 'https://www.patreon.com/', + 'submit_url' => 'https://www.patreon.com/create', + ], + 'tipeee' => [ + 'label' => 'Tipeee', + 'home_url' => 'https://tipeee.com/', + 'submit_url' => 'https://tipeee.com/register/', + ], + 'ulule' => [ + 'label' => 'Ulule', + 'home_url' => 'https://www.ulule.com/', + 'submit_url' => 'https://www.ulule.com/projects/create/#/', + ], + 'donorbox' => [ + 'label' => 'Donorbox', + 'home_url' => 'https://donorbox.org/', + 'submit_url' => 'https://donorbox.org/orgs/new', + ], + ], + ]; + + /** + * @return array + */ + public function getPlatformsByType(string $type): array + { + return self::DATA[$type] ?? []; + } + + /** + * @return null|array{label:string,home_url:string,submit_url:?string} + */ + public function findPlatformBySlug(string $type, string $slug): ?array + { + $data = self::DATA[$type] ?? []; + + if (! array_key_exists($slug, $data)) { + return null; + } + + return $data[$slug]; + } +} diff --git a/modules/Plugins/Commands/Add.php b/modules/Plugins/Commands/Add.php new file mode 100644 index 00000000..97e8aa28 --- /dev/null +++ b/modules/Plugins/Commands/Add.php @@ -0,0 +1,81 @@ + + */ + protected $arguments = [ + 'plugin' => 'The pluginKey and an optional version separated by an @. If version is not provided, the latest will be added by default.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + #[Override] + public function run(array $params): void + { + parent::run($params); + + $plugins = $this->parsePluginsParams($params); + + /** @var PluginsManager $cpm */ + $cpm = service('cpm'); + + $cpm->install($plugins); + } + + /** + * @param array $params + * @return array + */ + private function parsePluginsParams(array $params): array + { + $plugins = []; + foreach ($params as $param) { + preg_match( + '/^(?[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*)(@(?\S+))?\s*$/', + $param, + $matches, + ); + + if (array_key_exists('pluginKey', $matches)) { + $plugins[$matches['pluginKey']] = $matches['version'] ?? null; + } + } + + return $plugins; + } +} diff --git a/modules/Plugins/Commands/BaseCommand.php b/modules/Plugins/Commands/BaseCommand.php new file mode 100644 index 00000000..7cc27b01 --- /dev/null +++ b/modules/Plugins/Commands/BaseCommand.php @@ -0,0 +1,46 @@ + + */ + protected $options = [ + '--debug' => 'Get log trace to follow what is happening under the hood.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + * + * @return int|void + */ + public function run(array $params) + { + if (CLI::getOption('debug')) { + PluginsManagerLogger::$formatter = CpmFormatterDebug::class; + } else { + PluginsManagerLogger::$formatter = CpmFormatter::class; + } + + return 0; + } +} diff --git a/modules/Plugins/Commands/CpmFormatter.php b/modules/Plugins/Commands/CpmFormatter.php new file mode 100644 index 00000000..e312824c --- /dev/null +++ b/modules/Plugins/Commands/CpmFormatter.php @@ -0,0 +1,60 @@ + CLI::write( + sprintf('• adding plugin %s%s', CLI::color( + $log['context']['pluginKey'], + 'white', + ), $log['context']['constraint'] === null ? '' : '@' . CLI::color( + $log['context']['constraint'], + 'light_yellow', + )), + ), + 'add.end' => CLI::write( + sprintf('+ %s@%s added%s', $log['context']['pluginKey'], $log['context']['version'], PHP_EOL), + 'light_green', + ), + 'update.start' => CLI::write(sprintf('• updating plugin %s…', $log['context']['pluginKey'])), + 'update.end' => CLI::write( + '✔ ' . sprintf( + '%s updated to version %s%s', + $log['context']['pluginKey'], + $log['context']['version'], + PHP_EOL, + ), + 'light_green', + ), + 'remove.start' => CLI::write(sprintf('• removing plugin %s…', $log['context']['pluginKey'])), + 'remove.end' => CLI::write( + '- ' . sprintf('%s was removed%s', $log['context']['pluginKey'], PHP_EOL), + 'light_red', + ), + default => null, + }; + + if ($level === LogLevel::Warning) { + CLI::write('⚠️ ' . $log['message'], 'light_yellow'); + } + + if ($level === LogLevel::Error) { + CLI::newLine(); + CLI::write(' error ', 'white', 'red'); + CLI::error($log['message']); + CLI::newLine(); + + exit(1); // exit with error, something wrong happened + } + } +} diff --git a/modules/Plugins/Commands/CpmFormatterDebug.php b/modules/Plugins/Commands/CpmFormatterDebug.php new file mode 100644 index 00000000..417576b1 --- /dev/null +++ b/modules/Plugins/Commands/CpmFormatterDebug.php @@ -0,0 +1,42 @@ + CLI::write( + sprintf('%s %s', CLI::color($level->name, 'white', 'green'), json_encode( + $log, + JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, + )), + ), + LogLevel::Warning => CLI::write( + sprintf('%s %s', CLI::color($level->name, 'white', 'yellow'), json_encode( + $log, + JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, + )), + ), + LogLevel::Error => CLI::write( + sprintf('%s %s', CLI::color($level->name, 'white', 'red'), json_encode( + $log, + JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, + )), + ), + default => CLI::write( + sprintf('%s %s', CLI::color($level->name, 'white', 'blue'), json_encode( + $log, + JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, + )), + ), + }; + } +} diff --git a/modules/Plugins/Commands/CreatePlugin.php b/modules/Plugins/Commands/CreatePlugin.php new file mode 100644 index 00000000..c0bcafa0 --- /dev/null +++ b/modules/Plugins/Commands/CreatePlugin.php @@ -0,0 +1,153 @@ + ['use App\Entities\Podcast;'], + 'rssAfterChannel' => ['use App\Entities\Podcast;', 'use App\Libraries\RssFeed;'], + 'rssBeforeItem' => ['use App\Entities\Episode;'], + 'rssAfterItem' => ['use App\Entities\Episode;', 'use App\Libraries\RssFeed;'], + 'siteHead' => ['use use App\Libraries\HtmlHead'], + ]; + + protected const HOOKS_METHODS = [ + 'rssBeforeChannel' => ' public function rssBeforeChannel(Podcast $podcast): void + { + // YOUR CODE HERE + }', + 'rssAfterChannel' => ' public function rssAfterChannel(Podcast $podcast, RssFeed $channel): void + { + // YOUR CODE HERE + }', + 'rssBeforeItem' => ' public function rssBeforeItem(Episode $episode): void + { + // YOUR CODE HERE + }', + 'rssAfterItem' => ' public function rssAfterItem(Episode $episode, RssFeed $item): void + { + // YOUR CODE HERE + }', + 'siteHead' => ' public function siteHead(HtmlHead $head): void + { + // YOUR CODE HERE + }', + ]; + + /** + * @var string + */ + protected $name = 'plugins:create'; + + /** + * @var string + */ + protected $description = 'Generates a new plugin folder based on a template.'; + + /** + * Actually execute a command. + * + * @param list $params + */ + #[Override] + public function run(array $params): void + { + $pluginName = CLI::prompt( + 'Plugin name (/)', + 'acme/hello-world', + Manifest::$validation_rules['name'], + ); + CLI::newLine(); + $description = CLI::prompt('Description', '', Manifest::$validation_rules['description']); + CLI::newLine(); + $license = CLI::prompt('License', 'UNLICENSED', Manifest::$validation_rules['license']); + CLI::newLine(); + $hooks = CLI::promptByMultipleKeys('Which hooks do you want to implement?', Plugins::HOOKS); + + $nameParts = explode('/', $pluginName); + $vendor = $nameParts[0]; + $name = $nameParts[1]; + + /** @var PluginsConfig $pluginsConfig */ + $pluginsConfig = config('Plugins'); + + // 1. create plugin directory if not existent + $pluginDirectory = $pluginsConfig->folder . $vendor . DIRECTORY_SEPARATOR . $name; + if (! file_exists($pluginDirectory)) { + mkdir($pluginDirectory, 0755, true); + } + + // 2. get contents of templates + $manifestTemplate = file_get_contents(__DIR__ . '/plugin-template/manifest.tpl.json'); + + if (! $manifestTemplate) { + throw new Exception('Failed to get manifest template.'); + } + + $pluginClassTemplate = file_get_contents(__DIR__ . '/plugin-template/Plugin.tpl.php'); + + if (! $pluginClassTemplate) { + throw new Exception('Failed to get Plugin class template.'); + } + + // 3. edit templates' contents + $manifestContents = str_replace('"name": ""', '"name": "' . $pluginName . '"', $manifestTemplate); + $manifestContents = str_replace( + '"description": ""', + '"description": "' . $description . '"', + $manifestContents, + ); + $manifestContents = str_replace('"license": ""', '"license": "' . $license . '"', $manifestContents); + $manifestContents = str_replace( + '"hooks": []', + '"hooks": ["' . implode('", "', $hooks) . '"]', + $manifestContents, + ); + + $pluginClassName = str_replace( + ' ', + '', + ucwords(str_replace(['-', '_', '.'], ' ', $vendor . ' ' . $name)) . 'Plugin', + ); + $pluginClassContents = str_replace('class Plugin', 'class ' . $pluginClassName, $pluginClassTemplate); + + $allImports = []; + $allMethods = []; + foreach ($hooks as $hook) { + $allImports = [...$allImports, ...self::HOOKS_IMPORTS[$hook]]; + $allMethods = [...$allMethods, self::HOOKS_METHODS[$hook]]; + } + + $imports = implode(PHP_EOL, array_unique($allImports)); + $methods = implode(PHP_EOL . PHP_EOL, $allMethods); + $pluginClassContents = str_replace('// IMPORTS_HERE', $imports, $pluginClassContents); + $pluginClassContents = str_replace(' // HOOKS_HERE', $methods, $pluginClassContents); + + $manifest = $pluginDirectory . '/manifest.json'; + $pluginClass = $pluginDirectory . '/Plugin.php'; + + if (! file_put_contents($manifest, $manifestContents)) { + throw new Exception('Failed to create manifest.json file.'); + } + + if (! file_put_contents($pluginClass, $pluginClassContents)) { + throw new Exception('Failed to create Plugin class file.'); + } + + CLI::newLine(1); + CLI::write( + sprintf('Plugin %s created in %s', CLI::color($pluginName, 'white'), CLI::color($pluginDirectory, 'white')), + 'green', + ); + } +} diff --git a/modules/Plugins/Commands/Install.php b/modules/Plugins/Commands/Install.php new file mode 100644 index 00000000..11c80a03 --- /dev/null +++ b/modules/Plugins/Commands/Install.php @@ -0,0 +1,48 @@ + $params + */ + #[Override] + public function run(array $params): void + { + parent::run($params); + + /** @var PluginsManager $cpm */ + $cpm = service('cpm'); + + $cpm->installFromPluginsTxt(); + } +} diff --git a/modules/Plugins/Commands/Remove.php b/modules/Plugins/Commands/Remove.php new file mode 100644 index 00000000..6f54212f --- /dev/null +++ b/modules/Plugins/Commands/Remove.php @@ -0,0 +1,85 @@ + + */ + protected $arguments = [ + 'plugins' => 'One or more plugins as vendor/plugin', + ]; + + /** + * @param list $params + */ + #[Override] + public function run(array $params): int + { + parent::run($params); + + /** @var Plugins $plugins */ + $plugins = service('plugins'); + + /** @var PluginsManager $cpm */ + $cpm = service('cpm'); + + /** @var list $errors */ + $errors = []; + foreach ($params as $pluginKey) { + $plugin = $plugins->getPluginByKey($pluginKey); + + if ($plugin === null) { + $errors[] = sprintf('Plugin %s was not found.', $pluginKey); + continue; + } + + if (! $plugins->uninstall($plugin)) { + $errors[] = sprintf('Something happened when removing %s', $pluginKey); + break; + } + + // delete plugin folder + $cpm->remove($pluginKey); + } + + foreach ($errors as $error) { + CLI::write(' error ', 'white', 'red'); + CLI::error($error); + CLI::newLine(); + } + + return $errors === [] ? 0 : 1; + } +} diff --git a/modules/Plugins/Commands/Update.php b/modules/Plugins/Commands/Update.php new file mode 100644 index 00000000..08836bfe --- /dev/null +++ b/modules/Plugins/Commands/Update.php @@ -0,0 +1,65 @@ + + */ + protected $arguments = [ + 'plugin' => 'The pluginKey and an optional version separated by an @. If version is not provided, the latest will be added by default.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + * + * @return int|void + */ + #[Override] + public function run(array $params) + { + parent::run($params); + + if ($params === []) { + CLI::error('Missing pluginKey argument.'); + return 1; + } + + /** @var PluginsManager $cpm */ + $cpm = service('cpm'); + + $cpm->update($params[0]); + } +} diff --git a/modules/Plugins/Commands/plugin-template/Plugin.tpl.php b/modules/Plugins/Commands/plugin-template/Plugin.tpl.php new file mode 100644 index 00000000..edf615e5 --- /dev/null +++ b/modules/Plugins/Commands/plugin-template/Plugin.tpl.php @@ -0,0 +1,11 @@ +group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\Plugins\Controllers', + ], + static function ($routes): void { + $routes->group('plugins', static function ($routes): void { + $routes->get('/', 'PluginController::installed', [ + 'as' => 'plugins-installed', + 'filter' => 'permission:plugins.manage', + ]); + $routes->get('(:segment)', 'PluginController::vendor/$1', [ + 'as' => 'plugins-vendor', + 'filter' => 'permission:plugins.manage', + ]); + $routes->group('(:segment)/(:segment)', static function ($routes): void { + $routes->get('/', 'PluginController::view/$1/$2', [ + 'as' => 'plugins-view', + 'filter' => 'permission:plugins.manage', + ]); + $routes->get('settings', 'PluginController::settingsView/$1/$2', [ + 'as' => 'plugins-settings-general', + 'filter' => 'permission:plugins.manage', + ]); + $routes->post('settings', 'PluginController::settingsAction/$1/$2', [ + 'as' => 'plugins-settings-general-action', + 'filter' => 'permission:plugins.manage', + ]); + $routes->get('(:num)', 'PluginController::settingsView/$1/$2/$3', [ + 'as' => 'plugins-settings-podcast', + 'filter' => 'permission:podcast$3.edit', + ]); + $routes->post('(:num)', 'PluginController::settingsAction/$1/$2/$3', [ + 'as' => 'plugins-settings-podcast-action', + 'filter' => 'permission:podcast$3.edit', + ]); + $routes->get('(:num)/(:num)', 'PluginController::settingsView/$1/$2/$3/$4', [ + 'as' => 'plugins-settings-episode', + 'filter' => 'permission:podcast$3.episodes.edit', + ]); + $routes->post('(:num)/(:num)', 'PluginController::settingsAction/$1/$2/$3/$4', [ + 'as' => 'plugins-settings-episode-action', + 'filter' => 'permission:podcast$3.episodes.edit', + ]); + $routes->post('activate', 'PluginController::activate/$1/$2', [ + 'as' => 'plugins-activate', + 'filter' => 'permission:plugins.manage', + ]); + $routes->post('deactivate', 'PluginController::deactivate/$1/$2', [ + 'as' => 'plugins-deactivate', + 'filter' => 'permission:plugins.manage', + ]); + $routes->get('uninstall', 'PluginController::uninstall/$1/$2', [ + 'as' => 'plugins-uninstall', + 'filter' => 'permission:plugins.manage', + ]); + }); + }); + }, +); diff --git a/modules/Plugins/Config/Services.php b/modules/Plugins/Config/Services.php new file mode 100644 index 00000000..ea91b4d7 --- /dev/null +++ b/modules/Plugins/Config/Services.php @@ -0,0 +1,37 @@ +repositoryUrl, WRITEPATH, $config->folder, WRITEPATH . 'temp'); + } +} diff --git a/modules/Plugins/Controllers/PluginController.php b/modules/Plugins/Controllers/PluginController.php new file mode 100644 index 00000000..2028cdec --- /dev/null +++ b/modules/Plugins/Controllers/PluginController.php @@ -0,0 +1,362 @@ +plugins = service('plugins'); + } + + public function installed(): string + { + $pager = service('pager'); + + $page = (int) ($this->request->getGet('page') ?? 1); + $perPage = 10; + $total = $this->plugins->getInstalledCount(); + + $pager_links = $pager->makeLinks($page, $perPage, $total); + + $this->setHtmlHead(lang('Plugins.installed')); + return view('plugins/installed', [ + 'total' => $total, + 'plugins' => $this->plugins->getPlugins($page, $perPage), + 'pager_links' => $pager_links, + ]); + } + + public function vendor(string $vendor): string + { + $vendorPlugins = $this->plugins->getVendorPlugins($vendor); + + $this->setHtmlHead(lang('Plugins.installed')); + replace_breadcrumb_params([ + $vendor => $vendor, + ]); + return view('plugins/installed', [ + 'total' => count($vendorPlugins), + 'plugins' => $vendorPlugins, + 'pager_links' => '', + ]); + } + + public function view(string $vendor, string $package): string + { + + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->setHtmlHead($plugin->getTitle()); + replace_breadcrumb_params([ + $vendor => $vendor, + $package => $package, + ]); + return view('plugins/view', [ + 'plugin' => $plugin, + ]); + } + + public function settingsView( + string $vendor, + string $package, + ?string $podcastId = null, + ?string $episodeId = null, + ): string { + + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $type = 'general'; + $context = null; + $breadcrumbReplacements = [ + $vendor => $vendor, + $package => $package, + ]; + $data = [ + 'plugin' => $plugin, + ]; + + if ($podcastId !== null) { + $podcast = new PodcastModel() + ->getPodcastById((int) $podcastId); + + if (! $podcast instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + $type = 'podcast'; + $context = ['podcast', (int) $podcastId]; + $breadcrumbReplacements[0] = $podcast->handle; + $data['podcast'] = $podcast; + } + + if ($episodeId !== null) { + $episode = new EpisodeModel() + ->getEpisodeById((int) $episodeId); + + if (! $episode instanceof Episode) { + throw PageNotFoundException::forPageNotFound(); + } + + $type = 'episode'; + $context = ['episode', (int) $episodeId]; + $breadcrumbReplacements[1] = $episode->title; + $data['episode'] = $episode; + } + + $fields = $plugin->getSettingsFields($type); + + if ($fields === []) { + throw PageNotFoundException::forPageNotFound(); + } + + $data['type'] = $type; + $data['context'] = $context; + $data['fields'] = $fields; + + helper('form'); + $this->setHtmlHead(lang('Plugins.settingsTitle', [ + 'pluginTitle' => $plugin->getTitle(), + 'type' => $type, + ])); + replace_breadcrumb_params($breadcrumbReplacements); + return view('plugins/settings', $data); + } + + public function settingsAction( + string $vendor, + string $package, + ?string $podcastId = null, + ?string $episodeId = null, + ): RedirectResponse { + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $type = 'general'; + $context = null; + if ($podcastId !== null) { + $type = 'podcast'; + $context = ['podcast', (int) $podcastId]; + } + + if ($episodeId !== null) { + $type = 'episode'; + $context = ['episode', (int) $episodeId]; + } + + // construct validation rules first + $rules = []; + foreach ($plugin->getSettingsFields($type) as $field) { + $typeRules = $this->plugins::FIELDS_VALIDATIONS[$field->type]; + if (! in_array('permit_empty', $typeRules, true)) { + $typeRules[] = $field->optional ? 'permit_empty' : 'required'; + } + + if ($field->multiple) { + if ($field instanceof Group) { + foreach ($field->fields as $subField) { + $typeRules = $this->plugins::FIELDS_VALIDATIONS[$subField->type]; + if (! in_array('permit_empty', $typeRules, true)) { + $typeRules[] = $subField->optional ? 'permit_empty' : 'required'; + } + + $rules[sprintf('%s.*.%s', $field->key, $subField->key)] = [ + ...$typeRules, + ...$subField->validationRules, + ]; + } + } else { + $rules[$field->key . '.*'] = [...$typeRules, ...$field->validationRules]; + } + } elseif ($field instanceof Group) { + foreach ($field->fields as $subField) { + $typeRules = $this->plugins::FIELDS_VALIDATIONS[$subField->type]; + if (! in_array('permit_empty', $typeRules, true)) { + $typeRules[] = $subField->optional ? 'permit_empty' : 'required'; + } + + $rules[sprintf('%s.%s', $field->key, $subField->key)] = [ + ...$typeRules, + ...$subField->validationRules, + ]; + } + } else { + $rules[$field->key] = [...$typeRules, ...$field->validationRules]; + } + } + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validatedData = $this->validator->getValidated(); + + foreach ($plugin->getSettingsFields($type) as $field) { + $fieldValue = $validatedData[$field->key] ?? null; + + $this->plugins->setOption($plugin, $field->key, $this->castFieldValue($field, $fieldValue), $context); + } + + // clear cache after setting options + $plugin->clearCache(); + + return redirect()->back() + ->with('message', lang('Plugins.messages.saveSettingsSuccess', [ + 'pluginTitle' => $plugin->getTitle(), + ])); + } + + public function activate(string $vendor, string $package): RedirectResponse + { + + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->plugins->activate($plugin); + + // clear cache after activation + $plugin->clearCache(); + + return redirect()->back(); + } + + public function deactivate(string $vendor, string $package): RedirectResponse + { + + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->plugins->deactivate($plugin); + + // clear cache after deactivation + $plugin->clearCache(); + + return redirect()->back(); + } + + public function uninstall(string $vendor, string $package): RedirectResponse + { + + $plugin = $this->plugins->getPlugin($vendor, $package); + + if (! $plugin instanceof BasePlugin) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->plugins->uninstall($plugin); + + return redirect()->back(); + } + + private function castFieldValue(Field $field, mixed $fieldValue): mixed + { + if ($fieldValue === '' || $fieldValue === null) { + return null; + } + + $value = null; + if ($field->multiple) { + $value = []; + foreach ($fieldValue as $key => $val) { + if ($val === '') { + continue; + } + + if ($field instanceof Group) { + foreach ($val as $subKey => $subVal) { + /** @var Field|false $subField */ + $subField = array_column($field->fields, null, 'key')[$subKey] ?? false; + if (! $subField) { + continue; + } + + $v = $this->castValue($subVal, $subField->type); + if ($v) { + $value[$key][$subKey] = $v; + } + } + } else { + $value[$key] = $this->castValue($val, $field->type); + } + } + } elseif ($field instanceof Group) { + foreach ($fieldValue as $subKey => $subVal) { + /** @var Field|false $subField */ + $subField = array_column($field->fields, null, 'key')[$subKey] ?? false; + if (! $subField) { + continue; + } + + $v = $this->castValue($subVal, $subField->type); + if ($v) { + $value[$subKey] = $v; + } + } + } else { + $value = $this->castValue($fieldValue, $field->type); + } + + return $value === [] ? null : $value; + } + + private function castValue(mixed $value, string $type): mixed + { + if ($value === '' || $value === null) { + return null; + } + + return match ($this->plugins::FIELDS_CASTS[$type] ?? 'text') { + 'bool' => $value === 'yes', + 'int' => (int) $value, + 'uri' => new URI($value), + 'datetime' => Time::createFromFormat( + 'Y-m-d H:i', + $value, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()), + 'markdown' => new Markdown($value), + 'rss' => new RSS($value), + default => $value, + }; + } +} diff --git a/modules/Plugins/Core/BasePlugin.php b/modules/Plugins/Core/BasePlugin.php new file mode 100644 index 00000000..995fa272 --- /dev/null +++ b/modules/Plugins/Core/BasePlugin.php @@ -0,0 +1,389 @@ +key = sprintf('%s/%s', $vendor, $package); + + // TODO: cache manifest data + $manifestPath = $directory . '/manifest.json'; + + $this->manifest = new Manifest($this->key); + $this->manifest->loadFromFile($manifestPath); + + // check compatibility with Castopod version + if ($this->manifest->minCastopodVersion !== null && version_compare( + CP_VERSION, + $this->manifest->minCastopodVersion, + '<', + )) { + $this->status = PluginStatus::INCOMPATIBLE; + } else { + $this->status = get_plugin_setting($this->key, 'active') ? PluginStatus::ACTIVE : PluginStatus::INACTIVE; + } + + $this->iconSrc = $this->loadIcon($directory . '/icon.svg'); + + $this->readmeHTML = $this->loadMarkdownAsHTML($directory . '/README.md'); + + $this->licenseHTML = $this->loadMarkdownAsHTML($directory . '/LICENSE.md'); + } + + /** + * @param list|string $value + */ + public function __set(string $name, array|string $value): void + { + $this->{$name} = $value; + } + + #[Override] + public function rssBeforeChannel(Podcast $podcast): void + { + } + + #[Override] + public function rssAfterChannel(Podcast $podcast, RssFeed $channel): void + { + } + + #[Override] + public function rssBeforeItem(Episode $episode): void + { + } + + #[Override] + public function rssAfterItem(Episode $episode, RssFeed $item): void + { + } + + #[Override] + public function siteHead(HtmlHead $head): void + { + } + + final public function getGeneralSetting(string $key): mixed + { + return get_plugin_setting($this->key, $key); + } + + final public function getPodcastSetting(int $podcastId, string $key): mixed + { + return get_plugin_setting($this->key, $key, ['podcast', $podcastId]); + } + + final public function getEpisodeSetting(int $episodeId, string $key): mixed + { + return get_plugin_setting($this->key, $key, ['episode', $episodeId]); + } + + final public function clearCache(): void + { + foreach ($this->getHooks() as $hook) { + foreach (Plugins::CACHE_MAP[$hook] ?? [] as $cacheGlob) { + cache()->deleteMatching($cacheGlob); + } + } + } + + /** + * @return bool true on success, false on failure + */ + final public function activate(): bool + { + if ($this->status === PluginStatus::ACTIVE) { + return false; + } + + $this->setStatus(PluginStatus::ACTIVE); + + if ($this->status === PluginStatus::INACTIVE) { + return false; + } + + set_plugin_setting($this->key, 'active', true); + return true; + } + + final public function deactivate(): bool + { + if ($this->status !== PluginStatus::ACTIVE) { + return false; + } + + $this->setStatus(PluginStatus::INACTIVE); + set_plugin_setting($this->key, 'active', false); + + return true; + } + + final public function getStatus(): PluginStatus + { + return $this->status; + } + + final public function getDirectory(): string + { + return $this->directory; + } + + /** + * @return array + */ + final public function getManifestErrors(): array + { + return Manifest::getPluginErrors($this->key); + } + + final public function isHookDeclared(string $name): bool + { + return in_array($name, $this->manifest->hooks, true); + } + + final public function getVersion(): string + { + return $this->manifest->version; + } + + final public function getHomepage(): ?URI + { + return $this->manifest->homepage; + } + + final public function getRepository(): ?Repository + { + return $this->manifest->repository; + } + + /** + * @return list + */ + final public function getKeywords(): array + { + return $this->manifest->keywords; + } + + /** + * @return Person[] + */ + final public function getAuthors(): array + { + return $this->manifest->authors; + } + + final public function getIconSrc(): string + { + return $this->iconSrc; + } + + /** + * @return Field[] + */ + final public function getSettingsFields(string $type): array + { + $settings = $this->manifest->settings; + if (! $settings instanceof Settings) { + return []; + } + + return $settings->{$type}; + } + + final public function getMinCastopodVersion(): string + { + return $this->manifest->minCastopodVersion ?? ''; + } + + /** + * @return list + */ + final public function getHooks(): array + { + return $this->manifest->hooks; + } + + final public function getKey(): string + { + return $this->key; + } + + final public function getVendor(): string + { + return $this->vendor; + } + + final public function getPackage(): string + { + return $this->package; + } + + final public function getTitle(): string + { + $key = sprintf('Plugin.%s.title', $this->key); + /** @var string $title */ + $title = lang($key); + + if ($title === $key) { + return $this->manifest->name; + } + + return $title; + } + + final public function getDescription(): string + { + $key = sprintf('Plugin.%s.description', $this->key); + + /** @var string $description */ + $description = lang($key); + + if ($description === $key) { + return esc($this->manifest->description); + } + + return $description; + } + + final public function getReadmeHTML(): ?string + { + return $this->readmeHTML; + } + + final public function getLicense(): string + { + return $this->manifest->license ?? 'UNLICENSED'; + } + + final public function getLicenseHTML(): ?string + { + return $this->licenseHTML; + } + + /** + * @param PluginStatus::ACTIVE|PluginStatus::INACTIVE $value + */ + final protected function setStatus(PluginStatus $value): self + { + if ($this->getManifestErrors() !== []) { + $this->status = PluginStatus::INVALID; + + return $this; + } + + $this->status = $value; + + return $this; + } + + final protected function getOption(string $option): mixed + { + return get_plugin_setting($this->key, $option); + } + + final protected function setOption(string $option, mixed $value = null): void + { + set_plugin_setting($this->key, $option, $value); + } + + private function loadIcon(string $path): string + { + // TODO: cache icon + $svgIcon = @file_get_contents($path); + + if (! $svgIcon) { + return "data:image/svg+xml;utf8,%3Csvg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox='0 0 64 64'%3E%3Cpath fill='%2300564A' d='M0 0h64v64H0z'%2F%3E%3Cpath fill='%23E7F9E4' d='M25.3 18.7a5 5 0 1 1 9.7 1.6h7c1 0 1.7.8 1.7 1.7v7a5 5 0 1 1 0 9.4v7c0 .9-.8 1.6-1.7 1.6H18.7c-1 0-1.7-.7-1.7-1.7V22c0-1 .7-1.7 1.7-1.7h7a5 5 0 0 1-.4-1.6Z'%2F%3E%3C%2Fsvg%3E"; + } + + $encodedIcon = rawurlencode(str_replace(["\r", "\n"], ' ', $svgIcon)); + return 'data:image/svg+xml;utf8,' . str_replace( + ['%20', '%22', '%27', '%3D'], + [' ', "'", "'", '='], + $encodedIcon, + ); + } + + private function loadMarkdownAsHTML(string $path): ?string + { + // TODO: cache readme + $readmeMD = @file_get_contents($path); + + if (! $readmeMD) { + return null; + } + + $environment = new Environment([ + 'html_input' => 'escape', + 'allow_unsafe_links' => false, + 'host' => new URI(base_url()) + ->getHost(), + ]); + $environment->addExtension(new CommonMarkCoreExtension()); + + $environment->addExtension(new GithubFlavoredMarkdownExtension()); + $environment->addExtension(new SmartPunctExtension()); + + $environment->addEventListener( + DocumentParsedEvent::class, + static function (DocumentParsedEvent $event): void { + new ExternalLinkProcessor() + ->onDocumentParsed($event); + }, + ); + $environment->addEventListener( + DocumentParsedEvent::class, + static function (DocumentParsedEvent $event): void { + new ExternalImageProcessor() + ->onDocumentParsed($event); + }, + ); + + $converter = new MarkdownConverter($environment); + + return $converter->convert($readmeMD) + ->getContent(); + } +} diff --git a/modules/Plugins/Core/Markdown.php b/modules/Plugins/Core/Markdown.php new file mode 100644 index 00000000..2e6b1af7 --- /dev/null +++ b/modules/Plugins/Core/Markdown.php @@ -0,0 +1,46 @@ +markdown; + } + + public function renderHTML(): string + { + $config = [ + 'html_input' => 'escape', + 'allow_unsafe_links' => false, + ]; + + $environment = new Environment($config); + $environment->addExtension(new CommonMarkCoreExtension()); + $environment->addExtension(new AutolinkExtension()); + $environment->addExtension(new SmartPunctExtension()); + $environment->addExtension(new DisallowedRawHtmlExtension()); + + $converter = new MarkdownConverter($environment); + + return (string) $converter->convert($this->markdown); + } +} diff --git a/modules/Plugins/Core/PluginInterface.php b/modules/Plugins/Core/PluginInterface.php new file mode 100644 index 00000000..bd30aad5 --- /dev/null +++ b/modules/Plugins/Core/PluginInterface.php @@ -0,0 +1,23 @@ + + */ + public const HOOKS = ['rssBeforeChannel', 'rssAfterChannel', 'rssBeforeItem', 'rssAfterItem', 'siteHead']; + + public const CACHE_MAP = [ + 'rssBeforeChannel' => ['podcast*feed*'], + 'rssAfterChannel' => ['podcast*feed*'], + 'rssBeforeItem' => ['podcast*feed*'], + 'rssAfterItem' => ['podcast*feed*'], + 'siteHead' => ['page*'], + ]; + + public const FIELDS_VALIDATIONS = [ + 'checkbox' => ['permit_empty'], + 'datetime' => ['valid_date[Y-m-d H:i]'], + 'email' => ['valid_email'], + 'group' => ['permit_empty', 'is_list'], + 'html' => ['string'], + 'markdown' => ['string'], + 'number' => ['integer'], + 'radio-group' => ['string'], + 'rss' => ['string'], + 'select' => ['string'], + 'select-multiple' => ['permit_empty', 'is_list'], + 'text' => ['string'], + 'textarea' => ['string'], + 'toggler' => ['permit_empty'], + 'url' => ['valid_url_strict'], + ]; + + public const FIELDS_CASTS = [ + 'checkbox' => 'bool', + 'datetime' => 'datetime', + 'markdown' => 'markdown', + 'number' => 'int', + 'rss' => 'rss', + 'toggler' => 'bool', + 'url' => 'uri', + ]; + + /** + * @var array + */ + protected static array $plugins = []; + + /** + * @var array + */ + protected static array $pluginsByVendor = []; + + protected static int $installedCount = 0; + + protected static int $activeCount = 0; + + public function __construct( + protected PluginsConfig $config, + ) { + helper('plugins'); + + $this->registerPlugins(); + } + + /** + * @param value-of $name + * @param array $arguments + */ + public function __call(string $name, array $arguments): void + { + if (! in_array($name, static::HOOKS, true)) { + return; + } + + $this->runHook($name, $arguments); + } + + /** + * @return array + */ + public function getPlugins(int $page = 1, int $perPage = 12): array + { + return array_slice(static::$plugins, (($page - 1) * $perPage), $perPage); + } + + /** + * @return array + */ + public function getAllPlugins(): array + { + return static::$plugins; + } + + /** + * @return array + */ + public function getActivePlugins(): array + { + $activePlugins = []; + foreach (static::$plugins as $plugin) { + if ($plugin->getStatus() === PluginStatus::ACTIVE) { + $activePlugins[] = $plugin; + } + } + + return $activePlugins; + } + + /** + * @return array + */ + public function getPluginsWithPodcastSettings(): array + { + $pluginsWithPodcastSettings = []; + foreach (static::$plugins as $plugin) { + if ($plugin->getStatus() !== PluginStatus::ACTIVE) { + continue; + } + + if ($plugin->getSettingsFields('podcast') === []) { + continue; + } + + $pluginsWithPodcastSettings[] = $plugin; + } + + return $pluginsWithPodcastSettings; + } + + /** + * @return array + */ + public function getPluginsWithEpisodeSettings(): array + { + $pluginsWithEpisodeSettings = []; + foreach (static::$plugins as $plugin) { + if ($plugin->getStatus() !== PluginStatus::ACTIVE) { + continue; + } + + if ($plugin->getSettingsFields('episode') === []) { + continue; + } + + $pluginsWithEpisodeSettings[] = $plugin; + } + + return $pluginsWithEpisodeSettings; + } + + /** + * @return array + */ + public function getVendorPlugins(string $vendor): array + { + return static::$pluginsByVendor[$vendor] ?? []; + } + + public function getPlugin(string $vendor, string $package): ?BasePlugin + { + foreach ($this->getVendorPlugins($vendor) as $plugin) { + if ($plugin->getPackage() === $package) { + return $plugin; + } + } + + return null; + } + + public function getPluginByKey(string $key): ?BasePlugin + { + if (! str_contains($key, '/')) { + return null; + } + + $keyArray = explode('/', $key); + return $this->getPlugin($keyArray[0], $keyArray[1]); + } + + /** + * @param value-of $name + * @param array $arguments + */ + public function runHook(string $name, array $arguments): void + { + foreach (static::$plugins as $plugin) { + // only run hook on active plugins + if ($plugin->getStatus() !== PluginStatus::ACTIVE) { + continue; + } + + if (! $plugin->isHookDeclared($name)) { + continue; + } + + $plugin->{$name}(...$arguments); + } + } + + public function activate(BasePlugin $plugin): void + { + if ($plugin->activate()) { + ++self::$activeCount; + } + } + + public function deactivate(BasePlugin $plugin): void + { + if ($plugin->deactivate()) { + --self::$activeCount; + } + } + + /** + * @param ?array{'podcast'|'episode',int} $additionalContext + */ + public function setOption(BasePlugin $plugin, string $name, mixed $value, ?array $additionalContext = null): void + { + set_plugin_setting($plugin->getKey(), $name, $value, $additionalContext); + } + + public function getInstalledCount(): int + { + return static::$installedCount; + } + + public function getActiveCount(): int + { + return static::$activeCount; + } + + public function uninstall(BasePlugin $plugin): bool + { + // remove all settings data + $db = Database::connect(); + $builder = $db->table('settings'); + + $db->transStart(); + $builder->where('class', self::class); + $builder->like('context', sprintf('plugin:%s', $plugin->getKey() . '%')); + + if (! $builder->delete()) { + $db->transRollback(); + return false; + } + + return $db->transCommit(); + } + + protected function registerPlugins(): void + { + // search for plugins in plugins folder + $pluginsDirectories = glob($this->config->folder . '*/*', GLOB_ONLYDIR); + + if ($pluginsDirectories === false || $pluginsDirectories === []) { + return; + } + + foreach ($pluginsDirectories as $pluginDirectory) { + $vendor = basename(dirname($pluginDirectory)); + $package = basename($pluginDirectory); + + if (preg_match('~' . PLUGINS_KEY_PATTERN . '~', $vendor . '/' . $package) === false) { + continue; + } + + $className = str_replace( + ' ', + '', + ucwords(str_replace(['-', '_', '.'], ' ', $vendor . ' ' . $package)) . 'Plugin', + ); + + $pluginFile = $pluginDirectory . DIRECTORY_SEPARATOR . 'Plugin.php'; + spl_autoload_register(static function ($class) use (&$className, &$pluginFile): void { + if ($class !== $className) { + return; + } + + if (! file_exists($pluginFile)) { + return; + } + + include_once $pluginFile; + }, true); + + if (! class_exists($className)) { + continue; + } + + $plugin = new $className($vendor, $package, $pluginDirectory); + if (! $plugin instanceof BasePlugin) { + continue; + } + + static::$plugins[] = $plugin; + static::$pluginsByVendor[$vendor][] = $plugin; + ++static::$installedCount; + + if ($plugin->getStatus() === PluginStatus::ACTIVE) { + ++static::$activeCount; + } + } + } +} diff --git a/modules/Plugins/Core/RSS.php b/modules/Plugins/Core/RSS.php new file mode 100644 index 00000000..36a96fe7 --- /dev/null +++ b/modules/Plugins/Core/RSS.php @@ -0,0 +1,43 @@ +rss; + } + + /** + * @return ?RssFeed[] + */ + public function toSimpleRSS(): ?array + { + try { + $rssFeed = new RssFeed("{$this->rss}"); + } catch (Exception) { + return null; + } + + return [ + ...$rssFeed->children(), + ...$rssFeed->children(RssFeed::ATOM_NS, true), + ...$rssFeed->children(RssFeed::ITUNES_NS, true), + ...$rssFeed->children(RssFeed::PODCAST_NS, true), + ]; + } +} diff --git a/modules/Plugins/ExternalImageProcessor.php b/modules/Plugins/ExternalImageProcessor.php new file mode 100644 index 00000000..f5947aa3 --- /dev/null +++ b/modules/Plugins/ExternalImageProcessor.php @@ -0,0 +1,45 @@ +getDocument(); + $walker = $document->walker(); + while ($event = $walker->next()) { + $node = $event->getNode(); + + // Only stop at Link nodes when we first encounter them + if (! ($node instanceof Image) || ! $event->isEntering()) { + continue; + } + + $url = $node->getUrl(); + if ($this->isUrlExternal($url)) { + $node->detach(); + } + } + } + + private function isUrlExternal(string $url): bool + { + // Only look at http and https URLs + if (! preg_match('/^https?:\/\//', $url)) { + return false; + } + + $host = parse_url($url, PHP_URL_HOST); + + // TODO: load from environment's config + return $host !== new URI(base_url()) + ->getHost(); + } +} diff --git a/modules/Plugins/ExternalLinkProcessor.php b/modules/Plugins/ExternalLinkProcessor.php new file mode 100644 index 00000000..0297609c --- /dev/null +++ b/modules/Plugins/ExternalLinkProcessor.php @@ -0,0 +1,46 @@ +getDocument(); + $walker = $document->walker(); + while ($event = $walker->next()) { + $node = $event->getNode(); + + // Only stop at Link nodes when we first encounter them + if (! ($node instanceof Link) || ! $event->isEntering()) { + continue; + } + + $url = $node->getUrl(); + if ($this->isUrlExternal($url)) { + $node->data->append('attributes/target', '_blank'); + $node->data->append('attributes/rel', 'noopener noreferrer'); + } + } + } + + private function isUrlExternal(string $url): bool + { + // Only look at http and https URLs + if (! preg_match('/^https?:\/\//', $url)) { + return false; + } + + $host = parse_url($url, PHP_URL_HOST); + + // TODO: load from environment's config + return $host !== new URI(base_url()) + ->getHost(); + } +} diff --git a/modules/Plugins/Helpers/plugins_helper.php b/modules/Plugins/Helpers/plugins_helper.php new file mode 100644 index 00000000..3a2c926d --- /dev/null +++ b/modules/Plugins/Helpers/plugins_helper.php @@ -0,0 +1,83 @@ +get($key, $context); + } +} + +if (! function_exists('set_plugin_setting')) { + /** + * @param ?array{'podcast'|'episode',int} $additionalContext + */ + function set_plugin_setting( + string $pluginKey, + string $option, + mixed $value = null, + ?array $additionalContext = null, + ): void { + $key = sprintf('Plugins.%s', $option); + $context = sprintf('plugin:%s', $pluginKey); + + if ($additionalContext !== null) { + $context .= sprintf('+%s:%d', ...$additionalContext); + } + + setting() + ->set($key, $value, $context); + } +} + +if (! function_exists('load_plugins_translations')) { + /** + * @return array + */ + function load_plugins_translations(string $locale): array + { + $allPlugins = plugins() + ->getAllPlugins(); + + $translations = []; + foreach ($allPlugins as $plugin) { + $file = $plugin->getDirectory() . DIRECTORY_SEPARATOR . 'i18n' . DIRECTORY_SEPARATOR . $locale . '.json'; + + $jsonContents = @file_get_contents($file); + + if (! $jsonContents) { + continue; + } + + $contents = json_decode($jsonContents, true); + + if (! $contents) { + continue; + } + + $translations[$plugin->getKey()] = $contents; + } + + return $translations; + } +} diff --git a/modules/Plugins/Language/br/Plugin.php b/modules/Plugins/Language/br/Plugin.php new file mode 100644 index 00000000..36a992fa --- /dev/null +++ b/modules/Plugins/Language/br/Plugin.php @@ -0,0 +1,8 @@ + 'Plugins installed', + 'about' => 'About', + 'website' => 'Website', + 'repository' => 'Code repository', + 'authors' => 'Authors', + 'author_email' => 'Email {authorName}', + 'author_homepage' => '{authorName} homepage', + 'declaredHooks' => 'Declared hooks', + 'settings' => 'Settings', + 'settingsTitle' => '{type, select, + podcast {{pluginTitle} podcast settings} + episode {{pluginTitle} episode settings} + other {{pluginTitle} general settings} + }', + 'view' => 'View', + 'activate' => 'Activate', + 'deactivate' => 'Deactivate', + 'active' => 'Active', + 'inactive' => 'Inactive', + 'invalid' => 'Invalid', + 'incompatible' => 'Incompatible', + 'incompatible_hint' => 'Plugin requires Castopod v{minCastopodVersion} minimum.', + 'uninstall' => 'Uninstall', + 'keywords' => [ + 'podcasting20' => 'Podcasting 2.0', + 'seo' => 'SEO', + 'analytics' => 'Analytics', + 'accessibility' => 'Accessibility', + ], + 'noDescription' => 'No description', + 'noReadme' => 'No README file found.', + 'messages' => [ + 'saveSettingsSuccess' => '{pluginTitle} settings were successfully saved!', + ], + 'errors' => [ + 'manifestError' => 'Plugin manifest has errors', + 'manifestMissing' => 'Plugin manifest "{manifestPath}" is missing.', + 'manifestJsonInvalid' => 'Plugin manifest "{manifestPath}" is not a valid JSON.', + ], +]; diff --git a/modules/Plugins/Language/es/Plugin.php b/modules/Plugins/Language/es/Plugin.php new file mode 100644 index 00000000..36a992fa --- /dev/null +++ b/modules/Plugins/Language/es/Plugin.php @@ -0,0 +1,8 @@ + 'permit_empty|in_list[checkbox,datetime,email,group,html,markdown,number,radio-group,rss,select-multiple,select,text,textarea,toggler,url]', + 'key' => 'required|alpha_dash', + 'label' => 'required|string', + 'hint' => 'permit_empty|string', + 'helper' => 'permit_empty|string', + 'validationRules' => 'permit_empty|is_string_or_list', + 'optional' => 'permit_empty|is_boolean', + 'multiple' => 'permit_empty|is_boolean', + ]; + + protected string $type = 'text'; + + protected string $key; + + protected string $label; + + protected string $hint = ''; + + protected string $helper = ''; + + /** + * @var string[] + */ + protected array $validationRules = []; + + protected bool $optional = false; + + protected bool $multiple = false; + + public function getLabel(): string + { + return $this->getTranslated('label'); + } + + public function getHint(): string + { + return $this->getTranslated('hint'); + } + + public function getHelper(): string + { + return $this->getTranslated('helper'); + } + + /** + * @param string|list $values + */ + public function setValidationRules(string|array $values): void + { + $validationRules = []; + if (is_string($values)) { + $validationRules = explode('|', $values); + } + + $allowedRules = [ + 'alpha', + 'alpha_dash', + 'alpha_numeric', + 'alpha_numeric_punct', + 'alpha_numeric_space', + 'alpha_space', + 'decimal', + 'differs', + 'exact_length', + 'greater_than', + 'greater_than_equal_to', + 'hex', + 'in_list', + 'integer', + 'is_natural', + 'is_natural_no_zero', + 'less_than', + 'less_than_equal_to', + 'max_length', + 'min_length', + 'not_in_list', + 'regex_match', + 'valid_base64', + 'valid_date', + ]; + foreach ($validationRules as $rule) { + foreach ($allowedRules as $allowedRule) { + if (str_starts_with($rule, $allowedRule)) { + $this->validationRules[] = $rule; + } + } + } + } + + public function render(string $name, mixed $value, string $class = ''): string + { + throw new RuntimeException('Render function not defined in parent Field class'); + } + + private function getTranslated(string $property): string + { + $key = sprintf('Plugin.%s.settings.%s.%s.%s', $this->pluginKey, $this->type, $this->key, $property); + + /** @var string $i18nField */ + $i18nField = lang($key); + + if ($this->{$property} === '' || $i18nField === $key) { + return esc($this->{$property}); + } + + return esc($i18nField); + } +} diff --git a/modules/Plugins/Manifest/FieldInterface.php b/modules/Plugins/Manifest/FieldInterface.php new file mode 100644 index 00000000..2fcbaa23 --- /dev/null +++ b/modules/Plugins/Manifest/FieldInterface.php @@ -0,0 +1,10 @@ + 'permit_empty|is_boolean', + ]; + + protected bool $defaultValue = false; + + public function render(string $name, mixed $value, string $class = ''): string + { + $value = $value ? 'yes' : ''; + return <<{$this->label} + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Datetime.php b/modules/Plugins/Manifest/Fields/Datetime.php new file mode 100644 index 00000000..d7a5826f --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Datetime.php @@ -0,0 +1,37 @@ + 'permit_empty|valid_date', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Email.php b/modules/Plugins/Manifest/Fields/Email.php new file mode 100644 index 00000000..50f215f0 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Email.php @@ -0,0 +1,38 @@ + 'permit_empty|valid_email', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Group.php b/modules/Plugins/Manifest/Fields/Group.php new file mode 100644 index 00000000..2cb89f7d --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Group.php @@ -0,0 +1,36 @@ +injectRules(); + + parent::__construct($pluginKey); + } + + #[Override] + public function loadData(array $data): void + { + $data = $this->transformData($data); + + parent::loadData($data); + } + + public function render(string $name, mixed $value, string $class = ''): string + { + // TODO: render group, depending on multiple + throw new RuntimeException('Render function not defined in Group Field class'); + } +} diff --git a/modules/Plugins/Manifest/Fields/Html.php b/modules/Plugins/Manifest/Fields/Html.php new file mode 100644 index 00000000..f5f112cd --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Html.php @@ -0,0 +1,39 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + $value = htmlspecialchars($value ?? ''); + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Markdown.php b/modules/Plugins/Manifest/Fields/Markdown.php new file mode 100644 index 00000000..4105a628 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Markdown.php @@ -0,0 +1,37 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Number.php b/modules/Plugins/Manifest/Fields/Number.php new file mode 100644 index 00000000..949eea5a --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Number.php @@ -0,0 +1,38 @@ + 'permit_empty|numeric', + ]; + + protected ?int $defaultValue = null; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/RadioGroup.php b/modules/Plugins/Manifest/Fields/RadioGroup.php new file mode 100644 index 00000000..d7b38229 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/RadioGroup.php @@ -0,0 +1,57 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function __construct(string $pluginKey) + { + $this->injectRules(); + + parent::__construct($pluginKey); + } + + #[Override] + public function loadData(array $data): void + { + $data = $this->transformData($data); + + parent::loadData($data); + } + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + $options = esc(json_encode($this->getOptionsArray())); + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Rss.php b/modules/Plugins/Manifest/Fields/Rss.php new file mode 100644 index 00000000..3e085317 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Rss.php @@ -0,0 +1,40 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + $value = htmlspecialchars((string) $value); + $defaultValue = esc($this->defaultValue); + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Select.php b/modules/Plugins/Manifest/Fields/Select.php new file mode 100644 index 00000000..7fa8f9d2 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Select.php @@ -0,0 +1,64 @@ + 'permit_empty|string', + 'options' => 'is_list', + ]; + + protected array $casts = [ + 'options' => [Option::class], + ]; + + protected string $defaultValue = ''; + + public function __construct(string $pluginKey) + { + $this->injectRules(); + + parent::__construct($pluginKey); + } + + #[Override] + public function loadData(array $data): void + { + $data = $this->transformData($data); + + parent::loadData($data); + } + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + $options = esc(json_encode($this->getOptionsArray())); + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/SelectMultiple.php b/modules/Plugins/Manifest/Fields/SelectMultiple.php new file mode 100644 index 00000000..7a2e6e7f --- /dev/null +++ b/modules/Plugins/Manifest/Fields/SelectMultiple.php @@ -0,0 +1,63 @@ + $defaultValue + */ +class SelectMultiple extends Field +{ + use WithOptionsTrait; + + public static array $validation_rules = [ + 'defaultValue' => 'permit_empty|is_list', + ]; + + /** + * @var list + */ + protected array $defaultValue = []; + + public function __construct(string $pluginKey) + { + $this->injectRules(); + + parent::__construct($pluginKey); + } + + #[Override] + public function loadData(array $data): void + { + $data = $this->transformData($data); + + parent::loadData($data); + } + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + $options = esc(json_encode($this->getOptionsArray())); + $value = esc(json_encode($value)); + $defaultValue = esc(json_encode($this->defaultValue)); + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Text.php b/modules/Plugins/Manifest/Fields/Text.php new file mode 100644 index 00000000..67ee93aa --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Text.php @@ -0,0 +1,37 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Textarea.php b/modules/Plugins/Manifest/Fields/Textarea.php new file mode 100644 index 00000000..afb025a5 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Textarea.php @@ -0,0 +1,37 @@ + 'permit_empty|string', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Toggler.php b/modules/Plugins/Manifest/Fields/Toggler.php new file mode 100644 index 00000000..655dc8df --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Toggler.php @@ -0,0 +1,34 @@ + 'permit_empty|is_boolean', + ]; + + protected bool $defaultValue = false; + + public function render(string $name, mixed $value, string $class = ''): string + { + $value = $value ? 'yes' : ''; + return <<{$this->label} + HTML; + } +} diff --git a/modules/Plugins/Manifest/Fields/Url.php b/modules/Plugins/Manifest/Fields/Url.php new file mode 100644 index 00000000..3d712d62 --- /dev/null +++ b/modules/Plugins/Manifest/Fields/Url.php @@ -0,0 +1,39 @@ + 'permit_empty|valid_url_strict', + ]; + + protected string $defaultValue = ''; + + public function render(string $name, mixed $value, string $class = ''): string + { + $isRequired = $this->optional ? 'false' : 'true'; + return << + HTML; + } +} diff --git a/modules/Plugins/Manifest/Manifest.php b/modules/Plugins/Manifest/Manifest.php new file mode 100644 index 00000000..6c098d6c --- /dev/null +++ b/modules/Plugins/Manifest/Manifest.php @@ -0,0 +1,84 @@ + $keywords + * @property ?string $minCastopodVersion + * @property list $hooks + * @property ?Settings $settings + * @property ?Repository $repository + */ +class Manifest extends ManifestObject +{ + public static array $validation_rules = [ + 'name' => 'required|max_length[128]|regex_match[/^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*$/]', + 'version' => 'required|regex_match[/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/]', + 'description' => 'permit_empty|max_length[256]', + 'authors' => 'permit_empty|is_list', + 'homepage' => 'permit_empty|valid_url_strict', + 'license' => 'permit_empty|string', + 'private' => 'permit_empty|is_boolean', + 'submodule' => 'permit_empty|is_boolean', + 'keywords.*' => 'permit_empty', + 'minCastopodVersion' => 'permit_empty|regex_match[/^(0|[1-9]\d*)\.(0|[1-9]\d*)(\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/]', + 'hooks.*' => 'permit_empty|in_list[rssBeforeChannel,rssAfterChannel,rssBeforeItem,rssAfterItem,siteHead]', + 'settings' => 'permit_empty|is_list', + 'repository' => 'permit_empty|is_list', + ]; + + protected array $casts = [ + 'authors' => [Person::class], + 'homepage' => URI::class, + 'settings' => Settings::class, + 'repository' => Repository::class, + ]; + + protected ?string $name = '???'; + + protected ?string $version = 'X.Y.Z'; + + protected ?string $description = null; + + /** + * @var Person[] + */ + protected array $authors = []; + + protected ?URI $homepage = null; + + protected ?string $license = null; + + protected bool $private = false; + + protected bool $submodule = false; + + /** + * @var list + */ + protected array $keywords = []; + + protected ?string $minCastopodVersion = null; + + /** + * @var list + */ + protected array $hooks = []; + + protected ?Settings $settings = null; + + protected ?Repository $repository = null; +} diff --git a/modules/Plugins/Manifest/ManifestObject.php b/modules/Plugins/Manifest/ManifestObject.php new file mode 100644 index 00000000..4070d24f --- /dev/null +++ b/modules/Plugins/Manifest/ManifestObject.php @@ -0,0 +1,166 @@ + + */ + public static array $validation_rules = []; + + /** + * @var array + */ + protected array $casts = []; + + /** + * @var array> + */ + protected static array $errors = []; + + public function __construct( + protected readonly string $pluginKey, + ) { + self::$errors[$pluginKey] = []; + + $class = static::class; + $validation_rules = []; + $casts = []; + while ($class = get_parent_class($class)) { + $validation_rules = [...$validation_rules, ...get_class_vars($class)['validation_rules']]; + $casts = [...$casts, ...get_class_vars($class)['casts']]; + } + + $this::$validation_rules = [...$validation_rules, ...$this::$validation_rules]; + $this->casts = [...$casts, ...$this->casts]; + } + + public function __get(string $name): mixed + { + if (property_exists($this, $name)) { + // if a get method exists for this property, return that + $method = 'get' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name))); + if (method_exists($this, $method)) { + return $this->{$method}(); + } + + return $this->{$name}; + } + + throw new Exception('Undefined object property ' . static::class . '::' . $name); + } + + public function __isset(string $property): bool + { + return property_exists($this, $property); + } + + public function loadFromFile(string $manifestPath): void + { + $manifestContents = @file_get_contents($manifestPath); + + if (! $manifestContents) { + $manifestContents = '{}'; + $this->addError('manifest', lang('Plugins.errors.manifestMissing', [ + 'manifestPath' => $manifestPath, + ])); + } + + /** @var array|null $manifestData */ + $manifestData = json_decode($manifestContents, true); + + if ($manifestData === null) { + $manifestData = []; + $this->addError('manifest', lang('Plugins.errors.manifestJsonInvalid', [ + 'manifestPath' => $manifestPath, + ])); + } + + $this->loadData($manifestData); + } + + /** + * @param array $data + */ + public function loadData(array $data): void + { + /** @var Validation $validation */ + $validation = service('validation'); + + $validation->setRules($this::$validation_rules); + + if (! $validation->run($data)) { + foreach ($validation->getErrors() as $key => $message) { + $this->addError($key, $message); + } + + $validation->reset(); + } + + foreach ($validation->getValidated() as $key => $value) { + $method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); + if (is_callable([$this, $method])) { + $this->{$method}($value); + continue; + } + + if (array_key_exists($key, $this->casts)) { + $cast = $this->casts[$key]; + if (is_array($cast) && is_array($value)) { + foreach ($value as $valueKey => $valueElement) { + if (is_subclass_of($cast[0], self::class)) { + $manifestClass = $cast[0] === Field::class ? $this->getFieldClass( + $valueElement, + ) : $cast[0]; + $value[$valueKey] = new $manifestClass($this->pluginKey); + $value[$valueKey]->loadData($valueElement); + } else { + $value[$valueKey] = new $cast[0]($valueElement); + } + } + } elseif (is_subclass_of($cast, self::class)) { + $manifestClass = $cast === Field::class ? $this->getFieldClass($value) : $cast; + $valueElement = $value; + $value = new $manifestClass($this->pluginKey); + $value->loadData($valueElement ?? []); + } else { + $value = new $cast($value ?? []); + } + } + + $this->{$key} = $value; + } + } + + /** + * @return array + */ + public static function getPluginErrors(string $pluginKey): array + { + return self::$errors[$pluginKey]; + } + + protected function addError(string $errorKey, string $errorMessage): void + { + self::$errors[$this->pluginKey][$errorKey] = $errorMessage; + } + + /** + * @param array $data + */ + private function getFieldClass(array $data): string + { + $fieldType = $data['type'] ?? 'text'; + return rtrim(Field::class, "\Field") . '\\Fields\\' . str_replace( + ' ', + '', + ucwords(str_replace('-', ' ', $fieldType)), + ); + } +} diff --git a/modules/Plugins/Manifest/Option.php b/modules/Plugins/Manifest/Option.php new file mode 100644 index 00000000..ff15180b --- /dev/null +++ b/modules/Plugins/Manifest/Option.php @@ -0,0 +1,39 @@ + 'required|string', + 'value' => 'required|alpha_numeric_punct', + 'description' => 'permit_empty|string', + ]; + + protected string $label; + + protected string $value; + + protected string $description = ''; + + public function getTranslated(string $i18nKey, string $property): string + { + $key = sprintf('%s.%s.%s', $i18nKey, $this->value, $property); + + /** @var string $i18nField */ + $i18nField = lang($key); + + if ($this->{$property} === '' || $i18nField === $key) { + return esc($this->{$property}); + } + + return esc($i18nField); + } +} diff --git a/modules/Plugins/Manifest/Person.php b/modules/Plugins/Manifest/Person.php new file mode 100644 index 00000000..1a11c931 --- /dev/null +++ b/modules/Plugins/Manifest/Person.php @@ -0,0 +1,58 @@ +[^<>()]*)\s*(<(?.*)>)?\s*(\((?.*)\))?$/'; + + public static array $validation_rules = [ + 'name' => 'required', + 'email' => 'permit_empty|valid_email', + 'url' => 'permit_empty|valid_url_strict', + ]; + + /** + * @var array + */ + protected array $casts = [ + 'url' => URI::class, + ]; + + protected string $name; + + protected ?string $email = null; + + protected ?URI $url = null; + + #[Override] + public function loadData(array|string $data): void + { + if (is_string($data)) { + $result = preg_match(self::AUTHOR_STRING_PATTERN, $data, $matches); + + if (! $result) { + throw new Exception('Author string is not valid.'); + } + + $data = [ + 'name' => $matches['name'], + 'email' => $matches['email'] ?? null, + 'url' => $matches['url'] ?? null, + ]; + } + + parent::loadData($data); + } +} diff --git a/modules/Plugins/Manifest/Repository.php b/modules/Plugins/Manifest/Repository.php new file mode 100644 index 00000000..9a50398e --- /dev/null +++ b/modules/Plugins/Manifest/Repository.php @@ -0,0 +1,34 @@ + 'permit_empty|in_list[git]', + 'url' => 'required|valid_url_strict', + 'directory' => 'permit_empty', + ]; + + /** + * @var array + */ + protected array $casts = [ + 'url' => URI::class, + ]; + + protected string $type = 'git'; + + protected URI $url; + + protected ?string $directory = null; +} diff --git a/modules/Plugins/Manifest/Settings.php b/modules/Plugins/Manifest/Settings.php new file mode 100644 index 00000000..a30f3635 --- /dev/null +++ b/modules/Plugins/Manifest/Settings.php @@ -0,0 +1,62 @@ + 'permit_empty|is_list', + 'podcast' => 'permit_empty|is_list', + 'episode' => 'permit_empty|is_list', + ]; + + /** + * @var array + */ + protected array $casts = [ + 'general' => [Field::class], + 'podcast' => [Field::class], + 'episode' => [Field::class], + ]; + + /** + * @var Field[] + */ + protected array $general = []; + + /** + * @var Field[] + */ + protected array $podcast = []; + + /** + * @var Field[] + */ + protected array $episode = []; + + #[Override] + public function loadData(array $data): void + { + $newData = []; + foreach ($data as $key => $fields) { + $newFields = []; + foreach ($fields as $fieldKey => $field) { + $field['key'] = $fieldKey; + $newFields[] = $field; + } + + $newData[$key] = $newFields; + } + + parent::loadData($newData); + } +} diff --git a/modules/Plugins/Manifest/WithFieldsTrait.php b/modules/Plugins/Manifest/WithFieldsTrait.php new file mode 100644 index 00000000..72ac75a2 --- /dev/null +++ b/modules/Plugins/Manifest/WithFieldsTrait.php @@ -0,0 +1,45 @@ + 'is_list', + ]]; + $this->casts = [...$this->casts, ...[ + 'fields' => [Field::class], + ]]; + } + + /** + * @param array $data + * @return array + */ + public function transformData(array $data): array + { + if (array_key_exists('fields', $data)) { + $newFields = []; + foreach ($data['fields'] as $key => $field) { + $field['key'] = $key; + $newFields[] = $field; + } + + $data['fields'] = $newFields; + } + + return $data; + } +} diff --git a/modules/Plugins/Manifest/WithOptionsTrait.php b/modules/Plugins/Manifest/WithOptionsTrait.php new file mode 100644 index 00000000..a88b0ad3 --- /dev/null +++ b/modules/Plugins/Manifest/WithOptionsTrait.php @@ -0,0 +1,69 @@ + 'is_list', + ]]; + } + + if (isset($this->casts)) { + $this->casts = [...$this->casts, ...[ + 'options' => [Option::class], + ]]; + } + } + + /** + * @param array $data + * @return array + */ + public function transformData(array $data): array + { + if (array_key_exists('options', $data)) { + $newOptions = []; + foreach ($data['options'] as $key => $option) { + $option['value'] = $key; + $newOptions[] = $option; + } + + $data['options'] = $newOptions; + } + + return $data; + } + + /** + * @return array{label:string,value:string,description:string}[] + */ + public function getOptionsArray(): array + { + $i18nKey = sprintf('%s.settings.%s.%s.options', $this->pluginKey, $this->type, $this->key); + + $optionsArray = []; + foreach ($this->options as $option) { + $optionsArray[] = [ + 'value' => $option->value, + 'label' => $option->getTranslated($i18nKey, 'label'), + 'description' => $option->getTranslated($i18nKey, 'description'), + ]; + } + + return $optionsArray; + } +} diff --git a/modules/Plugins/Manifest/manifest.schema.json b/modules/Plugins/Manifest/manifest.schema.json new file mode 100644 index 00000000..08ecd0eb --- /dev/null +++ b/modules/Plugins/Manifest/manifest.schema.json @@ -0,0 +1,409 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "/schemas/manifest.json", + "title": "JSON schema for Castopod Plugins's manifest.json files", + "description": "The Castopod plugin manifest defines both metadata and behavior of a plugin", + "type": "object", + "properties": { + "name": { + "description": "The plugin name, including 'vendor-name/' prefix", + "type": "string", + "pattern": "^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*$", + "examples": ["acme/hello-world"] + }, + "version": { + "description": "The plugin's semantic version. See https://semver.org/", + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "examples": ["1.0.0"] + }, + "minCastopodVersion": { + "description": "The minimal version of Castopod for which the plugin is compatible with.", + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "examples": ["2.0"] + }, + "description": { + "description": "This helps people discover your plugin as it's listed in repositories", + "type": "string" + }, + "authors": { + "type": "array", + "items": { + "$ref": "#/$defs/person" + } + }, + "homepage": { + "description": "The URL to the plugin homepage", + "type": "string", + "format": "uri" + }, + "license": { + "description": "You should specify a license for your plugin so that people know how they are permitted to use it, and any restrictions you're placing on it.", + "default": "UNLICENSED", + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "AGPL-3.0-only", + "AGPL-3.0-or-later", + "Apache-2.0", + "BSL-1.0", + "GPL-3.0-only", + "GPL-3.0-or-later", + "LGPL-3.0-only", + "LGPL-3.0-or-later", + "MIT", + "MPL-2.0", + "Unlicense", + "UNLICENSED" + ] + } + ] + }, + "private": { + "type": "boolean", + "description": "If set to true, then repositories should refuse to publish it.", + "default": false + }, + "submodule": { + "type": "boolean", + "description": "Set to `true` if the plugin is part of a monorepo (i.e., in the same Git repository as other plugins). Releases should be tagged as `@` to ensure proper version indexing by plugin repositories.", + "default": false + }, + "keywords": { + "description": "This helps people discover your plugin as it's listed in repositories", + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "enum": [ + "accessibility", + "analytics", + "monetization", + "podcasting2", + "privacy", + "productivity", + "seo" + ] + } + ] + }, + "uniqueItems": true + }, + "hooks": { + "description": "The hooks used by the plugin.", + "type": "array", + "items": { + "enum": [ + "rssBeforeChannel", + "rssAfterChannel", + "rssBeforeItem", + "rssAfterItem", + "siteHead" + ] + }, + "uniqueItems": true + }, + "settings": { + "type": "object", + "properties": { + "general": { + "$ref": "#/$defs/fields" + }, + "podcast": { + "$ref": "#/$defs/fields" + }, + "episode": { + "$ref": "#/$defs/fields" + } + } + }, + "files": { + "description": "List of files to include in your plugin package. If you include a folder in the array, all files inside it will also be included.", + "type": "array", + "items": { + "type": "string" + } + }, + "repository": { + "description": "Specify the place where your plugin code lives. This is helpful for people who want to contribute.", + "type": ["object", "string"], + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "directory": { + "type": "string" + } + } + } + }, + "required": ["name", "version", "minCastopodVersion"], + "additionalProperties": false, + "$defs": { + "person": { + "description": "A person who has been involved in creating or maintaining this plugin.", + "type": ["object", "string"], + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "url": { + "type": "string", + "format": "uri" + } + } + }, + "fields": { + "type": "object", + "patternProperties": { + "^[A-Za-z]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/field" } + }, + "additionalProperties": false + }, + "field": { + "type": "object", + "properties": { + "type": { + "enum": [ + "checkbox", + "datetime", + "email", + "group", + "html", + "markdown", + "number", + "radio-group", + "rss", + "select-multiple", + "select", + "text", + "textarea", + "toggler", + "url" + ], + "default": "text" + }, + "label": { + "type": "string" + }, + "hint": { + "type": "string" + }, + "helper": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "validationRules": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "multiple": { + "type": "boolean" + } + }, + "required": ["label"], + "unevaluatedProperties": false, + "allOf": [ + { "$ref": "#/$defs/field-multiple-implies-options-is-required" }, + { "$ref": "#/$defs/require-fields-for-group-type" }, + { "$ref": "#/$defs/default-value-based-on-type" } + ] + }, + "option": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": ["label"], + "additionalProperties": false + }, + "field-multiple-implies-options-is-required": { + "if": { + "properties": { + "type": { + "enum": ["radio-group", "select", "select-multiple"] + } + } + }, + "then": { + "properties": { + "options": { + "type": "object", + "patternProperties": { + "^[A-Za-z0-9]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/option" } + }, + "additionalProperties": false + } + }, + "required": ["options"] + } + }, + "require-fields-for-group-type": { + "if": { + "properties": { + "type": { + "const": "group" + } + } + }, + "then": { + "properties": { + "fields": { + "type": "object", + "patternProperties": { + "^[A-Za-z]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/field" } + }, + "additionalProperties": false + } + }, + "required": ["fields"] + } + }, + "default-value-based-on-type": { + "allOf": [ + { + "if": { + "properties": { + "type": { + "enum": [ + "html", + "markdown", + "radio-group", + "rss", + "select", + "text", + "textarea" + ] + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "string" } + } + } + }, + { + "if": { + "properties": { + "type": { + "enum": ["checkbox", "toggler"] + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "boolean" } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "datetime" + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "string", "format": "date-time" } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "email" + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "string", "format": "email" } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "number" + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "number" } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "select-multiple" + } + } + }, + "then": { + "properties": { + "defaultValue": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "url" + } + } + }, + "then": { + "properties": { + "defaultValue": { "type": "string", "format": "uri" } + } + } + } + ] + } + } +} diff --git a/modules/PodcastImport/Commands/PodcastImport.php b/modules/PodcastImport/Commands/PodcastImport.php new file mode 100644 index 00000000..63c835e1 --- /dev/null +++ b/modules/PodcastImport/Commands/PodcastImport.php @@ -0,0 +1,599 @@ + $task->status === TaskStatus::Running, + ), + ); + + if ($currentImport instanceof PodcastImportTask) { + $currentImport->syncWithProcess(); + + if ($currentImport->status === TaskStatus::Running) { + // process is still running + throw new Exception('An import is already running.'); + } + + // continue if the task is not running anymore + } + + // Get the next queued import + $queuedImports = array_filter( + $importQueue, + static fn (PodcastImportTask $task): bool => $task->status === TaskStatus::Queued, + ); + $nextImport = end($queuedImports); + + if (! $nextImport instanceof PodcastImportTask) { + // no queued import task, stop process. + exit(0); + } + + $this->importTask = $nextImport; + + // retrieve user who created import task + $user = new UserModel() + ->find($this->importTask->created_by); + + if (! $user instanceof User) { + throw new Exception('Could not retrieve user with ID: ' . $this->importTask->created_by); + } + + $this->user = $user; + + CLI::write('Fetching and parsing RSS feed...'); + + ini_set('user_agent', 'Castopod/' . CP_VERSION); + $this->podcastFeed = new PodcastFeed($this->importTask->feed_url); + } + + #[Override] + public function run(array $params): void + { + // FIXME: getting named routes doesn't work from v4.3 anymore, so loading all routes before importing + service('routes') + ->loadRoutes(); + + try { + $this->init(); + + CLI::write('All good! Feed was parsed successfully!'); + + CLI::write( + 'Starting import for @' . $this->importTask->handle . ' using feed: ' . $this->importTask->feed_url, + ); + + // --- START IMPORT TASK --- + $this->importTask->start(); + + CLI::write('Checking if podcast is locked.'); + + if ($this->podcastFeed->channel->podcast_locked->getValue()) { + throw new Exception('🔒 Podcast is locked.'); + } + + CLI::write('Podcast is not locked, import can resume.'); + + // check if podcast to be imported already exists by guid if exists or handle otherwise + $podcastGuid = $this->podcastFeed->channel->podcast_guid->getValue(); + if ($podcastGuid !== null) { + $podcast = new PodcastModel() + ->where('guid', $podcastGuid) + ->first(); + } else { + $podcast = new PodcastModel() + ->where('handle', $this->importTask->handle) + ->first(); + } + + if ($podcast instanceof Podcast) { + if ($podcast->handle !== $this->importTask->handle) { + throw new Exception('Podcast was already imported with a different handle.'); + } + + CLI::write('Podcast handle already exists, using existing one.'); + $this->podcast = $podcast; + } + + helper(['media', 'misc', 'auth']); + + if (! $this->podcast instanceof Podcast) { + $this->podcast = $this->importPodcast(); + } + + CLI::write('Adding podcast platforms...'); + + $this->importPodcastPlatforms(); + + CLI::write('Adding persons - ' . count($this->podcastFeed->channel->podcast_persons) . ' elements.'); + + $this->importPodcastPersons(); + + $this->importEpisodes(); + + // set podcast publication date to the first ever published episode + $this->podcast->published_at = $this->getOldestEpisodePublicationDate( + $this->podcast->id, + ) ?? $this->podcast->created_at; + + $podcastModel = new PodcastModel(); + if (! $podcastModel->update($this->podcast->id, $this->podcast)) { + throw new Exception(print_r($podcastModel->errors(), true)); + } + + CLI::showProgress(false); + + // // done, set status to passed + $this->importTask->pass(); + } catch (Exception $exception) { + $this->error($exception->getMessage()); + log_message( + 'critical', + 'Error when importing ' . $this->importTask?->feed_url . PHP_EOL . $exception->getMessage() . PHP_EOL . $exception->getTraceAsString(), + ); + } + } + + private function getOldestEpisodePublicationDate(int $podcastId): ?Time + { + $result = new EpisodeModel() + ->builder() + ->selectMax('published_at', 'oldest_published_at') + ->where('podcast_id', $podcastId) + ->get() + ->getResultArray(); + + if ($result[0]['oldest_published_at'] === null) { + return null; + } + + return Time::createFromFormat('Y-m-d H:i:s', $result[0]['oldest_published_at']); + } + + private function importPodcast(): Podcast + { + $location = null; + if ($this->podcastFeed->channel->podcast_location->getValue() !== null) { + $location = new Location( + $this->podcastFeed->channel->podcast_location->getValue(), + $this->podcastFeed->channel->podcast_location->getAttribute('geo'), + $this->podcastFeed->channel->podcast_location->getAttribute('osm'), + ); + } + + if (($showNotes = $this->getShowNotes($this->podcastFeed->channel)) === null) { + throw new Exception('Missing channel show notes. Please include a tag.'); + } + + if (($coverUrl = $this->getCoverUrl($this->podcastFeed->channel)) === null) { + throw new Exception('Missing podcast cover. Please include an tag.'); + } + + if (($ownerName = $this->podcastFeed->channel->itunes_owner->itunes_name->getValue()) === null) { + throw new Exception( + 'Missing podcast owner name. Please include an tag inside the tag.', + ); + } + + if (($ownerEmail = $this->podcastFeed->channel->itunes_owner->itunes_email->getValue()) === null) { + throw new Exception( + 'Missing podcast owner email. Please include an tag inside the tag.', + ); + } + + $parentalAdvisory = null; + if ($this->podcastFeed->channel->itunes_explicit->getValue() !== null) { + $parentalAdvisory = $this->podcastFeed->channel->itunes_explicit->getValue() ? 'explicit' : 'clean'; + } + + $db = db_connect(); + $db->transStart(); + + $htmlConverter = new HtmlConverter(); + $podcast = new Podcast([ + 'created_by' => $this->user->id, + 'updated_by' => $this->user->id, + 'guid' => $this->podcastFeed->channel->podcast_guid->getValue(), + 'handle' => $this->importTask->handle, + 'imported_feed_url' => $this->importTask->feed_url, + 'new_feed_url' => url_to('podcast-rss-feed', $this->importTask->handle), + 'title' => $this->podcastFeed->channel->title->getValue(), + 'description_markdown' => $htmlConverter->convert($showNotes), + 'description_html' => $showNotes, + 'cover' => download_file($coverUrl), + 'banner' => null, + 'language_code' => $this->importTask->language, + 'category_id' => $this->importTask->category, + 'parental_advisory' => $parentalAdvisory, + 'owner_name' => $ownerName, + 'owner_email' => $ownerEmail, + 'publisher' => $this->podcastFeed->channel->itunes_author->getValue(), + 'type' => $this->podcastFeed->channel->itunes_type->getValue(), + 'copyright' => $this->podcastFeed->channel->copyright->getValue(), + 'is_blocked' => $this->podcastFeed->channel->itunes_block->getValue(), + 'is_completed' => $this->podcastFeed->channel->itunes_complete->getValue(), + 'location' => $location, + ]); + + $podcastModel = new PodcastModel(); + if (! ($podcastId = $podcastModel->insert($podcast, true))) { + $db->transRollback(); + throw new Exception(print_r($podcastModel->errors(), true)); + } + + $podcast->id = $podcastId; + + // set current user as podcast admin + // 1. create new group + config('AuthGroups') + ->generatePodcastAuthorizations($podcast->id); + add_podcast_group($this->user, $podcast->id, 'admin'); + + $db->transComplete(); // save podcast to database + + CLI::write('Podcast was successfully created!'); + + return $podcast; + } + + private function getShowNotes(Channel|Item $channelOrItem): ?string + { + if (! $channelOrItem instanceof Item) { + return $channelOrItem->description->getValue() ?? $channelOrItem->itunes_summary->getValue(); + } + + if ($channelOrItem->content_encoded->getValue() !== null) { + return $channelOrItem->content_encoded->getValue(); + } + + return $channelOrItem->description->getValue() ?? $channelOrItem->itunes_summary->getValue(); + } + + private function getCoverUrl(Channel|Item $channelOrItem): ?string + { + if ($channelOrItem->itunes_image->getAttribute('href') !== null) { + return $channelOrItem->itunes_image->getAttribute('href'); + } + + if ($channelOrItem instanceof Channel && $channelOrItem->image->url->getValue() !== null) { + return $channelOrItem->image->url->getValue(); + } + + return null; + } + + private function importPodcastPersons(): void + { + $personsCount = count($this->podcastFeed->channel->podcast_persons); + $currPersonsStep = 1; // for progress + foreach ($this->podcastFeed->channel->podcast_persons as $person) { + CLI::showProgress($currPersonsStep++, $personsCount); + $fullName = $person->getValue(); + $newPersonId = null; + $personModel = new PersonModel(); + if (($newPerson = $personModel->getPerson($fullName)) instanceof Person) { + $newPersonId = $newPerson->id; + } else { + $newPodcastPerson = new Person([ + 'created_by' => $this->user->id, + 'updated_by' => $this->user->id, + 'full_name' => $fullName, + 'unique_name' => slugify($fullName), + 'information_url' => $person->getAttribute('href'), + 'avatar' => download_file((string) $person->getAttribute('img')), + ]); + + if (! $newPersonId = $personModel->insert($newPodcastPerson)) { + throw new Exception(print_r($personModel->errors(), true)); + } + } + + $personGroup = $person->getAttribute('group'); + $personRole = $person->getAttribute('role'); + + // set default group and role if taxonomy is not found + $personGroupSlug = 'cast'; + $personRoleSlug = 'host'; + + if (array_key_exists(strtolower((string) $personGroup), ReversedTaxonomy::$taxonomy)) { + $personGroup = ReversedTaxonomy::$taxonomy[strtolower((string) $personGroup)]; + $personGroupSlug = $personGroup['slug']; + + if (array_key_exists(strtolower((string) $personRole), $personGroup['roles'])) { + $personRoleSlug = $personGroup['roles'][strtolower((string) $personRole)]['slug']; + } + } + + $podcastPersonModel = new PersonModel(); + if (! $podcastPersonModel->addPodcastPerson( + $this->podcast->id, + $newPersonId, + $personGroupSlug, + $personRoleSlug, + )) { + throw new Exception(print_r($podcastPersonModel->errors(), true)); + } + } + + CLI::showProgress(false); + } + + private function importPodcastPlatforms(): void + { + $platformTypes = [ + [ + 'name' => 'podcasting', + 'elements' => $this->podcastFeed->channel->podcast_ids, + 'count' => count($this->podcastFeed->channel->podcast_ids), + 'account_url_key' => 'url', + 'account_id_key' => 'id', + ], + [ + 'name' => 'social', + 'elements' => $this->podcastFeed->channel->podcast_socials, + 'count' => count($this->podcastFeed->channel->podcast_socials), + 'account_url_key' => 'accountUrl', + 'account_id_key' => 'accountId', + ], + [ + 'name' => 'funding', + 'elements' => $this->podcastFeed->channel->podcast_fundings, + 'count' => count($this->podcastFeed->channel->podcast_fundings), + 'account_url_key' => 'url', + 'account_id_key' => 'id', + ], + ]; + + $platforms = service('platforms'); + $platformModel = new PlatformModel(); + foreach ($platformTypes as $platformType) { + $platformsData = []; + $currPlatformStep = 1; // for progress + CLI::write($platformType['name'] . ' - ' . $platformType['count'] . ' elements'); + foreach ($platformType['elements'] as $platform) { + CLI::showProgress($currPlatformStep++, $platformType['count']); + $platformSlug = $platform->getAttribute('platform'); + $platformData = $platforms->findPlatformBySlug($platformType['name'], $platformSlug); + + if ($platformData === null) { + continue; + } + + $platformsData[] = [ + 'podcast_id' => $this->podcast->id, + 'type' => $platformType['name'], + 'slug' => $platformSlug, + 'link_url' => $platform->getAttribute($platformType['account_url_key']), + 'account_id' => $platform->getAttribute($platformType['account_id_key']), + 'is_visible' => 0, + ]; + } + + $platformModel->savePlatforms($this->podcast->id, $platformType['name'], $platformsData); + CLI::showProgress(false); + } + } + + private function importEpisodes(): void + { + helper('text'); + + $itemsCount = count($this->podcastFeed->channel->items); + $this->importTask->setEpisodesCount($itemsCount); + + CLI::write('Adding episodes - ' . $itemsCount . ' episodes'); + + $htmlConverter = new HtmlConverter(); + + $importedGUIDs = $this->getImportedGUIDs($this->podcast->id); + + $currEpisodesStep = 0; // for progress + $episodesNewlyImported = 0; + $episodesAlreadyImported = 0; + + // insert episodes in reverse order, from the last item in the list to the first + foreach (array_reverse($this->podcastFeed->channel->items) as $key => $item) { + CLI::showProgress(++$currEpisodesStep, $itemsCount); + + if (in_array($item->guid->getValue(), $importedGUIDs, true)) { + // do not import item if already imported + // (check that item with guid has already been inserted) + $this->importTask->setEpisodesAlreadyImported(++$episodesAlreadyImported); + continue; + } + + $db = db_connect(); + $db->transStart(); + + $location = null; + if ($item->podcast_location->getValue() !== null) { + $location = new Location( + $item->podcast_location->getValue(), + $item->podcast_location->getAttribute('geo'), + $item->podcast_location->getAttribute('osm'), + ); + } + + if (($showNotes = $this->getShowNotes($item)) === null) { + $db->transRollback(); + throw new Exception('Missing item show notes. Please include a tag to item ' . $key); + } + + $coverUrl = $this->getCoverUrl($item); + + $parentalAdvisory = null; + if ($item->itunes_explicit->getValue() !== null) { + $parentalAdvisory = $item->itunes_explicit->getValue() ? 'explicit' : 'clean'; + } + + $episode = new Episode([ + 'created_by' => $this->user->id, + 'updated_by' => $this->user->id, + 'podcast_id' => $this->podcast->id, + 'title' => $item->title->getValue(), + 'slug' => slugify((string) $item->title->getValue(), 120) . '-' . strtolower( + random_string('alnum', 5), + ), + 'guid' => $item->guid->getValue(), + 'audio' => download_file( + $item->enclosure->getAttribute('url'), + $item->enclosure->getAttribute('type'), + ), + 'description_markdown' => $htmlConverter->convert($showNotes), + 'description_html' => $showNotes, + 'cover' => $coverUrl ? download_file($coverUrl) : null, + 'parental_advisory' => $parentalAdvisory, + 'number' => $item->itunes_episode->getValue(), + 'season_number' => $item->itunes_season->getValue(), + 'type' => $item->itunes_episodeType->getValue(), + 'is_blocked' => $item->itunes_block->getValue(), + 'location' => $location, + 'is_premium' => $this->podcast->is_premium_by_default, + 'published_at' => $item->pubDate->getValue(), + ]); + + $episodeModel = new EpisodeModel(); + + if (! ($episodeId = $episodeModel->insert($episode, true))) { + $db->transRollback(); + throw new Exception(print_r($episodeModel->errors(), true)); + } + + $this->importEpisodePersons($episodeId, $item->podcast_persons); + + $this->importTask->setEpisodesNewlyImported(++$episodesNewlyImported); + + $db->transComplete(); + } + } + + /** + * @return string[] + */ + private function getImportedGUIDs(int $podcastId): array + { + $result = new EpisodeModel() + ->builder() + ->select('guid') + ->where('podcast_id', $podcastId) + ->get() + ->getResultArray(); + + return array_map(static fn (array $element) => $element['guid'], $result); + } + + /** + * @param PodcastPerson[] $persons + */ + private function importEpisodePersons(int $episodeId, array $persons): void + { + foreach ($persons as $person) { + $fullName = $person->getValue(); + $personModel = new PersonModel(); + $newPersonId = null; + if (($newPerson = $personModel->getPerson($fullName)) instanceof Person) { + $newPersonId = $newPerson->id; + } else { + $newPerson = new Person([ + 'created_by' => $this->user->id, + 'updated_by' => $this->user->id, + 'full_name' => $fullName, + 'unique_name' => slugify($fullName), + 'information_url' => $person->getAttribute('href'), + 'avatar' => download_file((string) $person->getAttribute('img')), + ]); + + if (! ($newPersonId = $personModel->insert($newPerson))) { + throw new Exception(print_r($personModel->errors(), true)); + } + } + + $personGroup = $person->getAttribute('group'); + $personRole = $person->getAttribute('role'); + + // set default group and role if taxonomy is not found + $personGroupSlug = 'cast'; + $personRoleSlug = 'host'; + + if (array_key_exists(strtolower((string) $personGroup), ReversedTaxonomy::$taxonomy)) { + $personGroup = ReversedTaxonomy::$taxonomy[strtolower((string) $personGroup)]; + $personGroupSlug = $personGroup['slug']; + + if (array_key_exists(strtolower((string) $personRole), $personGroup['roles'])) { + $personRoleSlug = $personGroup['roles'][strtolower((string) $personRole)]['slug']; + } + } + + $episodePersonModel = new PersonModel(); + if (! $episodePersonModel->addEpisodePerson( + $this->podcast->id, + $episodeId, + $newPersonId, + $personGroupSlug, + $personRoleSlug, + )) { + throw new Exception(print_r($episodePersonModel->errors(), true)); + } + } + } + + private function error(string $message): void + { + if ($this->importTask instanceof PodcastImportTask) { + $this->importTask->fail($message); + } + + CLI::error('[Error] ' . $message); + } +} diff --git a/modules/PodcastImport/Config/Routes.php b/modules/PodcastImport/Config/Routes.php new file mode 100644 index 00000000..ede5be52 --- /dev/null +++ b/modules/PodcastImport/Config/Routes.php @@ -0,0 +1,50 @@ +group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\PodcastImport\Controllers', + ], + static function ($routes): void { + $routes->get('imports', 'PodcastImportController::list', [ + 'as' => 'all-podcast-imports', + 'filter' => 'permission:podcasts.import', + ]); + $routes->get('imports/add', 'PodcastImportController::addToQueueView', [ + 'as' => 'podcast-imports-add', + 'filter' => 'permission:podcasts.import', + ]); + $routes->post('imports/add', 'PodcastImportController::addToQueueAction', [ + 'filter' => 'permission:podcasts.import', + ]); + $routes->get('imports/(:segment)/(:alpha)', 'PodcastImportController::taskAction/$1/$2', [ + 'as' => 'podcast-imports-task-action', + 'filter' => 'permission:podcasts.import', + ]); + + $routes->group('podcasts/(:num)', static function ($routes): void { + $routes->get('imports', 'PodcastImportController::podcastList/$1', [ + 'as' => 'podcast-imports', + 'filter' => 'permission:podcast$1.manage-import', + ]); + $routes->get('sync-feeds', 'PodcastImportController::syncImport/$1', [ + 'as' => 'podcast-imports-sync', + 'filter' => 'permission:podcast$1.manage-import', + ]); + $routes->post('sync-feeds', 'PodcastImportController::syncImportAttempt/$1', [ + 'as' => 'podcast-imports-sync', + 'filter' => 'permission:podcast$1.manage-import', + ]); + }); + }, +); diff --git a/modules/PodcastImport/Controllers/PodcastImportController.php b/modules/PodcastImport/Controllers/PodcastImportController.php new file mode 100644 index 00000000..d15037d2 --- /dev/null +++ b/modules/PodcastImport/Controllers/PodcastImportController.php @@ -0,0 +1,219 @@ +setHtmlHead(lang('Podcast.all_imports')); + return view('import/queue', [ + 'podcastImportsQueue' => get_import_tasks(), + ]); + } + + public function podcastList(int $podcastId): string + { + if (! ($podcast = new PodcastModel()->getPodcastById($podcastId)) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + helper('podcast_import'); + + $this->setHtmlHead(lang('Podcast.all_imports')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('import/podcast_queue', [ + 'podcast' => $podcast, + 'podcastImportsQueue' => get_import_tasks($podcast->handle), + ]); + } + + public function addToQueueView(): string + { + helper(['form', 'misc']); + + $languageOptions = new LanguageModel() + ->getLanguageOptions(); + $categoryOptions = new CategoryModel() + ->getCategoryOptions(); + + $data = [ + 'languageOptions' => $languageOptions, + 'categoryOptions' => $categoryOptions, + 'browserLang' => get_browser_language($this->request->getServer('HTTP_ACCEPT_LANGUAGE')), + ]; + + $this->setHtmlHead(lang('Podcast.import')); + return view('import/add_to_queue', $data); + } + + public function addToQueueAction(): RedirectResponse + { + $rules = [ + 'handle' => 'required|regex_match[/^[a-zA-Z0-9\_]{1,32}$/]', + 'imported_feed_url' => 'required|valid_url_strict', + 'language' => 'required', + 'category' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + // TODO: check that handle is not already in use + + $importTask = new PodcastImportTask([ + 'handle' => $validData['handle'], + 'feed_url' => $validData['imported_feed_url'], + 'language' => $validData['language'], + 'category' => $validData['category'], + 'status' => TaskStatus::Queued, + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'created_at' => Time::now(), + 'updated_at' => Time::now(), + ]); + + $importTask->save(); + + return redirect()->route('all-podcast-imports') + ->with('message', lang('PodcastImport.messages.importTaskQueued')); + } + + public function syncImport(int $podcastId): string + { + if (! ($podcast = new PodcastModel()->getPodcastById($podcastId)) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + helper('form'); + + $this->setHtmlHead(lang('PodcastImport.syncForm.title')); + replace_breadcrumb_params([ + 0 => $podcast->at_handle, + ]); + return view('import/podcast_sync', [ + 'podcast' => $podcast, + ]); + } + + public function syncImportAttempt(int $podcastId): RedirectResponse + { + if (! ($podcast = new PodcastModel()->getPodcastById($podcastId)) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + $rules = [ + 'feed_url' => 'valid_url_strict', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + // create update task in podcastImport + $importTask = new PodcastImportTask([ + 'handle' => $podcast->handle, + 'feed_url' => $validData['feed_url'], + 'language' => $podcast->language_code, + 'category' => $podcast->category_id, + 'status' => TaskStatus::Queued, + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'created_at' => Time::now(), + 'updated_at' => Time::now(), + ]); + + $importTask->save(); + + return redirect()->route('podcast-imports', [$podcastId]) + ->with('message', lang('PodcastImport.messages.syncTaskQueued')); + } + + public function taskAction(string $taskId, string $action): RedirectResponse + { + /** @var array $importQueue */ + $importQueue = service('settings') + ->get('Import.queue') ?? []; + + if (! array_key_exists($taskId, $importQueue)) { + throw PageNotFoundException::forPageNotFound(); + } + + $importTask = $importQueue[$taskId]; + switch ($action) { + case 'cancel': + if ($importTask->status === TaskStatus::Running || $importTask->status === TaskStatus::Queued) { + $importTask->cancel(); + + return redirect()->back() + ->with('message', lang('PodcastImport.messages.canceled')); + } + + return redirect()->back() + ->with('error', lang('PodcastImport.messages.notRunning')); + case 'retry': + if ($importTask->status === TaskStatus::Running || $importTask->status === TaskStatus::Queued) { + return redirect()->back() + ->with('error', lang('PodcastImport.messages.alreadyRunning')); + } + + $newImportTask = new PodcastImportTask([ + 'handle' => $importTask->handle, + 'feed_url' => $importTask->feed_url, + 'language' => $importTask->language, + 'category' => $importTask->category, + 'status' => TaskStatus::Queued, + 'created_by' => user_id(), + 'updated_by' => user_id(), + 'created_at' => Time::now(), + 'updated_at' => Time::now(), + ]); + + $newImportTask->save(); + + return redirect()->back() + ->with('message', lang('PodcastImport.messages.retried')); + case 'delete': + $importTask->delete(); + return redirect()->back() + ->with('message', lang('PodcastImport.messages.deleted')); + default: + throw new Exception('Task action ' . $action . ' was not implemented'); + } + } +} diff --git a/modules/PodcastImport/Entities/PodcastImportTask.php b/modules/PodcastImport/Entities/PodcastImportTask.php new file mode 100644 index 00000000..b0de2f95 --- /dev/null +++ b/modules/PodcastImport/Entities/PodcastImportTask.php @@ -0,0 +1,242 @@ + $data + */ + public function __construct(array $data) + { + parent::__construct($data); + + if (! array_key_exists('id', $data)) { + $this->id = md5($this->feed_url . Time::now()); + } + } + + public function getProgress(): float + { + if ($this->episodes_count === null) { + return 0; + } + + return $this->episodes_imported / $this->episodes_count; + } + + public function getEpisodesImported(): int + { + return $this->episodes_newly_imported + $this->episodes_already_imported; + } + + public function setEpisodesNewlyImported(int $episodesImported): void + { + $this->episodes_newly_imported = $episodesImported; + + $this->save(); + } + + public function setEpisodesAlreadyImported(int $episodesImported): void + { + $this->episodes_already_imported = $episodesImported; + + $this->save(); + } + + public function setEpisodesCount(int $episodesCount): void + { + $this->episodes_count = $episodesCount; + + $this->save(); + } + + public function getDuration(): int + { + if ($this->duration === null && $this->started_at !== null && $this->ended_at !== null) { + $this->duration = ($this->started_at->difference($this->ended_at)) + ->getSeconds(); + } + + return $this->duration; + } + + public function start(): void + { + if ($this->process_id !== null) { + throw new Exception('Task is already running!'); + } + + $processId = getmypid(); + + if ($processId === false) { + throw new Exception('Error Processing Request', 1); + } + + $this->process_id = $processId; + $this->started_at = Time::now(); + $this->status = TaskStatus::Running; + $this->save(); + + service('settings') + ->set('Import.current', $this->handle); + } + + public function pass(): void + { + $this->process_id = null; + $this->ended_at = Time::now(); + $this->status = TaskStatus::Passed; + + $this->save(); + + service('settings') + ->forget('Import.current'); + } + + public function cancel(): void + { + if ($this->status !== TaskStatus::Running && $this->status !== TaskStatus::Queued) { + throw new Exception('Task can only be canceled if running or queued.'); + } + + if ($this->isProcessRunning()) { + // kill process + $isProcessKilled = posix_kill($this->process_id, 9); + + if (! $isProcessKilled) { + throw new Exception('Something wrong happened, process could not be killed.'); + } + } + + $this->process_id = null; + $this->status = TaskStatus::Canceled; + $this->ended_at = Time::now(); + $this->save(); + } + + public function delete(): void + { + if ($this->isProcessRunning()) { + $this->cancel(); + } + + $importQueue = service('settings') + ->get('Import.queue') ?? []; + + if ($importQueue === []) { + return; + } + + unset($importQueue[$this->id]); + + service('settings') + ->set('Import.queue', $importQueue); + } + + public function fail(string $message): void + { + $this->error = $message; + + $this->status = TaskStatus::Failed; + $this->ended_at = Time::now(); + $this->save(); + + service('settings') + ->forget('Import.current'); + } + + public function save(): void + { + $importQueue = service('settings') + ->get('Import.queue') ?? []; + + $now = Time::now(); + + if (! array_key_exists($this->id, $importQueue)) { + $this->created_at = $now; + } + + $this->updated_at = $now; + + $importQueue[$this->id] = $this; + + service('settings') + ->set('Import.queue', $importQueue); + } + + public function syncWithProcess(): void + { + if ($this->status !== TaskStatus::Running && $this->process_id !== null) { + $this->process_id = null; + $this->save(); + return; + } + + if ($this->status === TaskStatus::Running && $this->process_id === null) { + $this->fail('Running task has no process id set.'); + return; + } + + if (! $this->isProcessRunning()) { + $this->fail('Process was killed.'); + return; + } + } + + private function isProcessRunning(): bool + { + if ($this->process_id === null) { + return false; + } + + return posix_getpgid($this->process_id) !== false; + } +} diff --git a/modules/PodcastImport/Entities/TaskStatus.php b/modules/PodcastImport/Entities/TaskStatus.php new file mode 100644 index 00000000..53246d0f --- /dev/null +++ b/modules/PodcastImport/Entities/TaskStatus.php @@ -0,0 +1,14 @@ +get('Import.queue') ?? []; + + if ($podcastHandle !== null) { + $podcastImportsQueue = array_filter( + $podcastImportsQueue, + static fn (PodcastImportTask $importTask): bool => $importTask->handle === $podcastHandle, + ); + } + + usort($podcastImportsQueue, static function (PodcastImportTask $a, PodcastImportTask $b): int { + if ($a->status === $b->status) { + return $a->created_at->isAfter($b->created_at) ? -1 : 1; + } + + if ($a->status === TaskStatus::Running) { + return -1; + } + + if ($a->status === TaskStatus::Queued && $b->status !== TaskStatus::Running) { + return -1; + } + + return $a->created_at->isAfter($b->created_at) ? -1 : 1; + }); + + return $podcastImportsQueue; + } +} diff --git a/modules/PodcastImport/Language/ar/PodcastImport.php b/modules/PodcastImport/Language/ar/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ar/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/br/PodcastImport.php b/modules/PodcastImport/Language/br/PodcastImport.php new file mode 100644 index 00000000..c4f01d81 --- /dev/null +++ b/modules/PodcastImport/Language/br/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Enporzhiañ', + 'text' => 'Emañ {podcastTitle} o vezañ enporzhiet.', + 'cta' => 'Gwelet stad an enporzh', + ], + 'old_podcast_section_title' => 'Ar podkast da vezañ enporzhiet', + 'old_podcast_legal_disclaimer_title' => 'Menegoù lezennel', + 'old_podcast_legal_disclaimer' => + 'Bezit sur oc\'h aotreet da enporzhiañ ar podkast-mañ a-raok en ober. Eilañ ha skignañ ur podkast hep kaout an aotre a zo heñvel ouzh dambreziñ ha gallout a reer bezañ kaset d\'al lez-varn.', + 'imported_feed_url' => 'URL ar wazh', + 'imported_feed_url_hint' => 'Rankout a ra ar wazh bezañ er furmad xml pe rss.', + 'new_podcast_section_title' => 'Ar podkast nevez', + 'lock_import' => + 'Gwarezet eo ar wazh-mañ. Ne c\'hallit ket enporzhiañ anezhi. Ma\'z oc\'h ar perc\'henn·ez, dibrennit anezhi war ar savenn orin.', + 'submit' => 'Ouzhpennañ an enporzh d\'al lost', + 'queue' => [ + 'status' => [ + 'label' => 'Statud', + 'queued' => 'el lost', + 'queued_hint' => 'Emañ an enporzh el lost.', + 'canceled' => 'nullet', + 'canceled_hint' => 'Nullet eo bet an enporzh.', + 'running' => 'war ar stern', + 'running_hint' => 'Emañ an enporzh war ar stern.', + 'failed' => 'c\'hwitet', + 'failed_hint' => 'An enporzh n\'eo ket bet graet: fazi skript.', + 'passed' => 'berzh', + 'passed_hint' => 'Enporzhiet eo bet gant berzh!', + ], + 'feed' => 'Gwazh', + 'duration' => 'Padelezh an enporzh', + 'imported_episodes' => 'Rannoù enporzhiet', + 'imported_episodes_hint' => '{newlyImportedCount} enporzhiet nevez zo, {alreadyImportedCount} enporzhiet en holl.', + 'actions' => [ + 'cancel' => 'Nullañ', + 'retry' => 'Klask en-dro', + 'delete' => 'Dilemel', + ], + ], + 'syncForm' => [ + 'title' => 'Sinkronekaat ar gwazhoù', + 'feed_url' => 'URL ar wazh', + 'feed_url_hint' => 'URL ar wazh ho peus c\'hoant da sinkronekaat ouzh ar podkast-mañ.', + 'submit' => 'Ouzhpennañ d\'al lost', + ], + 'messages' => [ + 'canceled' => 'An enporzh zo bet nullet gant berzh!', + 'notRunning' => 'Ne c\'haller ket nullañ an enporzh rak n\'eo ket krog al labour.', + 'alreadyRunning' => 'Emañ an enporzh war ar stern. Gallout a rit nullañ anezhañ a-raok klask en-dro.', + 'retried' => 'Ouzhpennet eo bet an enporzh d\'al lost, klasket e vo en-dro dindan berr!', + 'deleted' => 'An enporzh zo bet dilamet gant berzh!', + 'importTaskQueued' => 'Un enporzh nevez zo bet ouzhpennet d\'al lost, kroget e vo dindan berr!', + 'syncTaskQueued' => 'Un enporzh nevez zo bet ouzhpennet d\'al lost, kroget e vo ar sinkronekaat dindan berr!', + ], +]; diff --git a/modules/PodcastImport/Language/ca/PodcastImport.php b/modules/PodcastImport/Language/ca/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ca/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/da/PodcastImport.php b/modules/PodcastImport/Language/da/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/da/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/de/PodcastImport.php b/modules/PodcastImport/Language/de/PodcastImport.php new file mode 100644 index 00000000..0cfa75f6 --- /dev/null +++ b/modules/PodcastImport/Language/de/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'Importstatus anzeigen', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'in Warteschlangen', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'abgebrochen', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'läuft', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'fehlgeschlagen', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'bestanden', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Abbrechen', + 'retry' => 'Erneut versuchen', + 'delete' => 'Löschen', + ], + ], + 'syncForm' => [ + 'title' => 'Feeds synchronisieren', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Zur Warteschlange hinzufügen', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/el/PodcastImport.php b/modules/PodcastImport/Language/el/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/el/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/en/PodcastImport.php b/modules/PodcastImport/Language/en/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/en/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/es/PodcastImport.php b/modules/PodcastImport/Language/es/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/es/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/eu/PodcastImport.php b/modules/PodcastImport/Language/eu/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/eu/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/fa/PodcastImport.php b/modules/PodcastImport/Language/fa/PodcastImport.php new file mode 100644 index 00000000..cf5f4592 --- /dev/null +++ b/modules/PodcastImport/Language/fa/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'درون‌ریزی', + 'text' => '{podcastTitle} دارد درون‌ریخته می‌شود.', + 'cta' => 'دیدن وضعیت درون‌ریزی', + ], + 'old_podcast_section_title' => 'پادکست برای درون‌ریزی', + 'old_podcast_legal_disclaimer_title' => 'سلب مسئولیت حقوقی', + 'old_podcast_legal_disclaimer' => + 'پیش از درون‌ریزی مطمئن شوید حقوق این پادکست را دارید. رونوشت و پخش یک پادکست بدون حقوق مناسب دزدی دریایی حساب شده و قابل پیگرد است.', + 'imported_feed_url' => 'نشانی خوراک', + 'imported_feed_url_hint' => 'خورام باید در قالب xml یا rss باشد.', + 'new_podcast_section_title' => 'پادکست جدید', + 'lock_import' => + 'این خوراک محافظت شده است. نمی‌توانید درون‌ریزیش کنید. اگر مالکش هستید، روی بن‌سازهٔ اصلی قفل‌گشاییش کنید.', + 'submit' => 'افزودن درون‌ریزی به صف', + 'queue' => [ + 'status' => [ + 'label' => 'وضعیت', + 'queued' => 'صف شده', + 'queued_hint' => 'وظیفهٔ درون‌ریزی منتظر پردازش است.', + 'canceled' => 'لغو شده', + 'canceled_hint' => 'وظیفهٔ درون‌ریزی لغو شد.', + 'running' => 'درحال اجرا', + 'running_hint' => 'وظیفهٔ درون‌ریزی در حال پردازش است.', + 'failed' => 'شکست خورده', + 'failed_hint' => 'وظیفهٔ درون‌ریزی نتوانست کامل شود: شکست کدنوشته.', + 'passed' => 'قبول شده', + 'passed_hint' => 'وظیفهٔ درون‌ریزی با موفّقیت کامل شد!', + ], + 'feed' => 'خوراک', + 'duration' => 'طول درون‌ریزی', + 'imported_episodes' => 'قسمت‌های درون‌ریخته', + 'imported_episodes_hint' => '{newlyImportedCount} به تازگی درون‌ریخته. {alreadyImportedCount} از پیش درون‌ریخته.', + 'actions' => [ + 'cancel' => 'لغو', + 'retry' => 'تلاش دوباره', + 'delete' => 'حذف', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'وظیفهٔ درون‌ریزی با موفّقیت لغو شد!', + 'notRunning' => 'نمی‌توان وظیفهٔ درون‌ریزی را لغو کرد؛ چرا که در حال اجرا نیست.', + 'alreadyRunning' => 'وظیفهٔ درون‌ریزی در حال اجراست. پیش از تلاش دوباره باید لغوش کنید.', + 'retried' => 'وظیفهٔ درون‌ریزی صف شد. به زودی دوباره انجام خواهد شد!', + 'deleted' => 'وظیفهٔ درون‌ریزی با موفّقیت حذف شد!', + 'importTaskQueued' => 'وظیفه‌ای جدید صف شد. درون‌ریزی به زودی آغاز خواهد شد!', + 'syncTaskQueued' => 'وظیفهٔ درون‌ریزی جدیدی صف شد. هم‌گام سازی به زودی آغاز خواهد شد!', + ], +]; diff --git a/modules/PodcastImport/Language/fr-ca/PodcastImport.php b/modules/PodcastImport/Language/fr-ca/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/fr-ca/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/fr/PodcastImport.php b/modules/PodcastImport/Language/fr/PodcastImport.php new file mode 100644 index 00000000..c9187b7d --- /dev/null +++ b/modules/PodcastImport/Language/fr/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importation', + 'text' => '{podcastTitle} est actuellement en cours d\'import.', + 'cta' => 'Voir l\'état d\'import', + ], + 'old_podcast_section_title' => 'Le podcast à importer', + 'old_podcast_legal_disclaimer_title' => 'Avertissement légal', + 'old_podcast_legal_disclaimer' => + 'Assurez-vous d’être détenteur des droits du podcast avant de l’importer. Copier et diffuser un podcast sans en détenir les droits est assimilable à de la contrefaçon et est passible de poursuites.', + 'imported_feed_url' => 'Adresse du flux', + 'imported_feed_url_hint' => 'Le flux doit être au format xml ou rss.', + 'new_podcast_section_title' => 'Le nouveau podcast', + 'lock_import' => + 'Ce flux est protégé. Vous ne pouvez pas l’importer. Si en vous êtes le propriétaire, déverrouillez-le sur la plate-forme d’origine.', + 'submit' => 'Ajouter l\'import à la file d\'attente', + 'queue' => [ + 'status' => [ + 'label' => 'État', + 'queued' => 'en attente', + 'queued_hint' => 'L’import est dans la file d’attente.', + 'canceled' => 'annulé', + 'canceled_hint' => 'L’import a été annulé.', + 'running' => 'en cours', + 'running_hint' => 'L’import est en cours de traitement.', + 'failed' => 'échec', + 'failed_hint' => 'L’import n’a pas pu se terminer : échec du script.', + 'passed' => 'succès', + 'passed_hint' => 'L’import a été complété avec succès !', + ], + 'feed' => 'Flux', + 'duration' => 'Durée de l’import', + 'imported_episodes' => 'Épisodes importés', + 'imported_episodes_hint' => '{newlyImportedCount} vient d\'être importé, {alreadyImportedCount} a déjà été importé.', + 'actions' => [ + 'cancel' => 'Annuler', + 'retry' => 'Réessayer', + 'delete' => 'Supprimer', + ], + ], + 'syncForm' => [ + 'title' => 'Synchroniser les flux', + 'feed_url' => 'Adresse du flux', + 'feed_url_hint' => 'L\'URL du flux que vous voulez synchroniser avec le podcast actuel.', + 'submit' => 'Ajouter à la file d\'attente', + ], + 'messages' => [ + 'canceled' => 'L’import a été annulé avec succès !', + 'notRunning' => 'Impossible d’annuler l’import car il n’est pas en cours d’exécution.', + 'alreadyRunning' => 'L’import est déjà en cours d’exécution. Vous devez l’annuler avant de réessayer.', + 'retried' => 'L’import a été placé dans la file d’attente, il sera exécuté sous peu !', + 'deleted' => 'L’import a bien été supprimé !', + 'importTaskQueued' => 'Une nouvelle tâche a été mise attente, l’import va bientôt commencer !', + 'syncTaskQueued' => 'Une nouvelle tâche a été mise attente, la synchronisation va bientôt commencer !', + ], +]; diff --git a/modules/PodcastImport/Language/fr2/PodcastImport.php b/modules/PodcastImport/Language/fr2/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/fr2/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/gd/PodcastImport.php b/modules/PodcastImport/Language/gd/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/gd/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/gl/PodcastImport.php b/modules/PodcastImport/Language/gl/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/gl/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/id/PodcastImport.php b/modules/PodcastImport/Language/id/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/id/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/it/PodcastImport.php b/modules/PodcastImport/Language/it/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/it/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/ja/PodcastImport.php b/modules/PodcastImport/Language/ja/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ja/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/kk/PodcastImport.php b/modules/PodcastImport/Language/kk/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/kk/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/ko/PodcastImport.php b/modules/PodcastImport/Language/ko/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ko/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/nl/PodcastImport.php b/modules/PodcastImport/Language/nl/PodcastImport.php new file mode 100644 index 00000000..831e798b --- /dev/null +++ b/modules/PodcastImport/Language/nl/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importeren', + 'text' => '{podcastTitle} wordt momenteel geïmporteerd.', + 'cta' => 'Bekijk importstatus', + ], + 'old_podcast_section_title' => 'De te importeren podcast', + 'old_podcast_legal_disclaimer_title' => 'Wettelijke disclaimer', + 'old_podcast_legal_disclaimer' => + 'Zorg ervoor dat je de rechten hebt voor deze podcast voordat je deze importeert. Het kopiëren en uitzenden van een podcast zonder de juiste rechten is piraterij en kan vervolgd worden.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'De feed moet in xml of rss formaat zijn.', + 'new_podcast_section_title' => 'De nieuwe podcast', + 'lock_import' => + 'Deze feed is beschermd. U kunt deze niet importeren. Als u de eigenaar bent, ontgrendel het op het oorsprongsplatform.', + 'submit' => 'Import toevoegen aan wachtrij', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'in wachtrij', + 'queued_hint' => 'Import taak is in afwachting van verwerking.', + 'canceled' => 'geannuleerd', + 'canceled_hint' => 'Importtaak is geannuleerd.', + 'running' => 'actief', + 'running_hint' => 'Import taak wordt verwerkt.', + 'failed' => 'mislukt', + 'failed_hint' => 'Import taak kon niet voltooid worden: script mislukt.', + 'passed' => 'geslaagd', + 'passed_hint' => 'Import taak is succesvol voltooid!', + ], + 'feed' => 'Feed', + 'duration' => 'Duur van importeren', + 'imported_episodes' => 'Geïmporteerde afleveringen', + 'imported_episodes_hint' => '{newlyImportedCount} onlangs geïmporteerd, {alreadyImportedCount} reeds geïmporteerd.', + 'actions' => [ + 'cancel' => 'Annuleer', + 'retry' => 'Opnieuw proberen', + 'delete' => 'Verwijderen', + ], + ], + 'syncForm' => [ + 'title' => 'Feeds synchroniseren', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'De feed-URL die u wilt synchroniseren met de huidige podcast.', + 'submit' => 'Aan wachtrij toevoegen', + ], + 'messages' => [ + 'canceled' => 'Import taak is succesvol geannuleerd!', + 'notRunning' => 'De Import taak kan niet worden geannuleerd omdat deze niet wordt uitgevoerd.', + 'alreadyRunning' => 'Import taak is al actief. U kunt deze annuleren voordat u opnieuw probeert.', + 'retried' => 'Import taak is in de wachtrij gezet, deze zal binnenkort opnieuw worden geprobeerd!', + 'deleted' => 'Import taak is succesvol verwijderd!', + 'importTaskQueued' => 'Een nieuwe taak is in de wachtrij gezet, de import zal binnenkort beginnen!', + 'syncTaskQueued' => 'Een nieuwe taak is in de wachtrij gezet, de import zal binnenkort beginnen!', + ], +]; diff --git a/modules/PodcastImport/Language/nn-no/PodcastImport.php b/modules/PodcastImport/Language/nn-no/PodcastImport.php new file mode 100644 index 00000000..83cdd088 --- /dev/null +++ b/modules/PodcastImport/Language/nn-no/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importerer', + 'text' => '{podcastTitle} blir importert.', + 'cta' => 'Sjå status på importen', + ], + 'old_podcast_section_title' => 'Podkast å importera', + 'old_podcast_legal_disclaimer_title' => 'Juridisk ansvarsfråskriving', + 'old_podcast_legal_disclaimer' => + 'Syt for at du har rettane til podkasten før du importerer han. Å kopiera og kringkasta ein podkast utan løyve er ulovleg og straffbart.', + 'imported_feed_url' => 'URL til straumen', + 'imported_feed_url_hint' => 'Straumen må vera i xml- eller rss-format.', + 'new_podcast_section_title' => 'Den nye podkasten', + 'lock_import' => + 'Denne straumen er verna. Du kan ikkje importera han. Viss du er eigaren, må du låsa han opp på den originale plattforma.', + 'submit' => 'Legg importen i køen', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'i kø', + 'queued_hint' => 'Importjobben ventar på å bli utført.', + 'canceled' => 'avbrote', + 'canceled_hint' => 'Importjobben vart avbroten.', + 'running' => 'køyrer', + 'running_hint' => 'Utfører importoppgåva.', + 'failed' => 'mislukka', + 'failed_hint' => 'Greidde ikkje fullføra importen: skriptfeil.', + 'passed' => 'utført', + 'passed_hint' => 'Importen var vellukka.', + ], + 'feed' => 'Straum', + 'duration' => 'Kor lenge importen vara', + 'imported_episodes' => 'Importerte episodar', + 'imported_episodes_hint' => '{newlyImportedCount} nyss importerte, {alreadyImportedCount} allereie importerte.', + 'actions' => [ + 'cancel' => 'Avbryt', + 'retry' => 'Prøv på nytt', + 'delete' => 'Slett', + ], + ], + 'syncForm' => [ + 'title' => 'Synkroniser straumar', + 'feed_url' => 'URL til straumen', + 'feed_url_hint' => 'URL til straumen du vil synkronisera med denne podkasten.', + 'submit' => 'Legg til i køen', + ], + 'messages' => [ + 'canceled' => 'Importen vart avbroten.', + 'notRunning' => 'Kan ikkje avbryta importen, fordi han ikkje køyrer.', + 'alreadyRunning' => 'Importen er i gang. Du kan avbryta han før du prøver på nytt.', + 'retried' => 'Importjobben er lagt i køen, og vil bli prøvd på nytt straks.', + 'deleted' => 'Importjobben er sletta.', + 'importTaskQueued' => 'Ein ny jobb er lagd i køen, og importen startar straks.', + 'syncTaskQueued' => 'Ein ny importjobb er lagd i køen, og synkroniseringa startar straks.', + ], +]; diff --git a/modules/PodcastImport/Language/oc/PodcastImport.php b/modules/PodcastImport/Language/oc/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/oc/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/pl/PodcastImport.php b/modules/PodcastImport/Language/pl/PodcastImport.php new file mode 100644 index 00000000..525f4327 --- /dev/null +++ b/modules/PodcastImport/Language/pl/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importowanie', + 'text' => '{podcastTitle} jest obecnie importowany.', + 'cta' => 'Zobacz status importu', + ], + 'old_podcast_section_title' => 'Podcast do zaimportowania', + 'old_podcast_legal_disclaimer_title' => 'Zastrzeżenie prawne', + 'old_podcast_legal_disclaimer' => + 'Upewnij się, że masz prawa do tego podcastu zanim go zaimportujesz. Kopiowanie i nadawanie podcastu bez odpowiednich praw jest piractwem i podlega ściganiu.', + 'imported_feed_url' => 'Adres URL kanału', + 'imported_feed_url_hint' => 'Kanał musi być w formacie xml lub rss.', + 'new_podcast_section_title' => 'Nowy podcast', + 'lock_import' => + 'Ten kanał jest chroniony. Nie możesz go zaimportować. Jeśli jesteś jego właścicielem — usuń ochronę na platformie, z której pochodzi.', + 'submit' => 'Dodaj import do kolejki', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'w kolejce', + 'queued_hint' => 'Import czeka na przetworzenie.', + 'canceled' => 'anulowano', + 'canceled_hint' => 'Zadanie importu zostało anulowane.', + 'running' => 'w toku', + 'running_hint' => 'Import jest przetwarzany.', + 'failed' => 'niepowodzenie', + 'failed_hint' => 'Zadanie importu nie powiodło się: błąd skryptu.', + 'passed' => 'powodzenie', + 'passed_hint' => 'Zadanie importu zostało zakończone pomyślnie!', + ], + 'feed' => 'Kanał', + 'duration' => 'Czas trwania importu', + 'imported_episodes' => 'Zaimportowane odcinki', + 'imported_episodes_hint' => '{newlyImportedCount} nowoimportowanych, {alreadyImportedCount} już zaimportowanych.', + 'actions' => [ + 'cancel' => 'Anuluj', + 'retry' => 'Ponów', + 'delete' => 'Usuń', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronizuj kanały', + 'feed_url' => 'Adres URL kanału', + 'feed_url_hint' => 'URL kanału, który chcesz zsynchronizować z bieżącym podcastem.', + 'submit' => 'Dodaj do kolejki', + ], + 'messages' => [ + 'canceled' => 'Zadanie importu zostało pomyślnie anulowane!', + 'notRunning' => 'Nie można anulować importu, ponieważ nie jest on uruchomiony.', + 'alreadyRunning' => 'Zadanie importu jest już uruchomione. Możesz je anulować przed ponowną próbą.', + 'retried' => 'Zadanie importu zostało umieszczone w kolejce, zostanie ono wkrótce ponowione!', + 'deleted' => 'Zadanie importu zostało pomyślnie usunięte!', + 'importTaskQueued' => 'Nowe zadanie zostało dodane, import rozpocznie się wkrótce!', + 'syncTaskQueued' => 'Nowe zadanie importu zostało dodane, synchronizacja rozpocznie się wkrótce!', + ], +]; diff --git a/modules/PodcastImport/Language/pt-br/PodcastImport.php b/modules/PodcastImport/Language/pt-br/PodcastImport.php new file mode 100644 index 00000000..ae81ff90 --- /dev/null +++ b/modules/PodcastImport/Language/pt-br/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importando', + 'text' => '{podcastTitle} está sendo importado no momento.', + 'cta' => 'Ver status de importação', + ], + 'old_podcast_section_title' => 'O podcast para importar', + 'old_podcast_legal_disclaimer_title' => 'Aviso legal', + 'old_podcast_legal_disclaimer' => + 'Certifique-se de possuir os direitos para esse podcast antes de importá-lo. Copiar e transmitir um podcast sem os direitos adequados é pirataria e corre-se o risco de processo legal.', + 'imported_feed_url' => 'URL do feed', + 'imported_feed_url_hint' => 'O feed deve estar no formato xml ou rss.', + 'new_podcast_section_title' => 'O novo podcast', + 'lock_import' => + 'Este feed está protegido. Você não pode importá-lo. Se é o dono, desbloqueie-o na plataforma de origem.', + 'submit' => 'Adicionar importação à fila', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'na fila', + 'queued_hint' => 'Tarefa de importação está aguardando para ser processada.', + 'canceled' => 'cancelado', + 'canceled_hint' => 'Tarefa de importação foi cancelada.', + 'running' => 'executando', + 'running_hint' => 'Tarefa de importação está sendo processada.', + 'failed' => 'falhou', + 'failed_hint' => 'Tarefa de importação não pôde ser concluída: falha no script.', + 'passed' => 'aprovado', + 'passed_hint' => 'Tarefa de importação foi concluída com sucesso!', + ], + 'feed' => 'Feed', + 'duration' => 'Duração da importação', + 'imported_episodes' => 'Episódios importados', + 'imported_episodes_hint' => '{newlyImportedCount} recém importado, {alreadyImportedCount} já importado.', + 'actions' => [ + 'cancel' => 'Cancelar', + 'retry' => 'Tente novamente', + 'delete' => 'Excluir', + ], + ], + 'syncForm' => [ + 'title' => 'Sincronizar o feed', + 'feed_url' => 'URL do feed', + 'feed_url_hint' => 'A URL do feed que você deseja sincronizar com o podcast atual.', + 'submit' => 'Adicionar à fila', + ], + 'messages' => [ + 'canceled' => 'Tarefa de importação foi cancelada com sucesso!', + 'notRunning' => 'Não é possível cancelar a tarefa de importação, pois ela não está em execução.', + 'alreadyRunning' => 'Tarefa de Importação já está em execução. Você pode cancelá-la antes de tentar novamente.', + 'retried' => 'Tarefa de importação foi enfileirada, ela será repetida em breve!', + 'deleted' => 'Tarefa de importação foi cancelada com sucesso!', + 'importTaskQueued' => 'Uma nova tarefa foi colocada na fila, a importação será iniciada em breve!', + 'syncTaskQueued' => 'Uma nova tarefa de importação foi colocada na fila, a sincronização começará em breve!', + ], +]; diff --git a/modules/PodcastImport/Language/pt/PodcastImport.php b/modules/PodcastImport/Language/pt/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/pt/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/ro/PodcastImport.php b/modules/PodcastImport/Language/ro/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ro/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/ru/PodcastImport.php b/modules/PodcastImport/Language/ru/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/ru/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/sk/PodcastImport.php b/modules/PodcastImport/Language/sk/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/sk/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/sr-latn/PodcastImport.php b/modules/PodcastImport/Language/sr-latn/PodcastImport.php new file mode 100644 index 00000000..504175b7 --- /dev/null +++ b/modules/PodcastImport/Language/sr-latn/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Uvoz', + 'text' => '{podcastTitle} se trenutno uvozi.', + 'cta' => 'Pogledaj status uvoza', + ], + 'old_podcast_section_title' => 'Podkast koji se uvozi', + 'old_podcast_legal_disclaimer_title' => 'Pravno odricanje od odgovornosti', + 'old_podcast_legal_disclaimer' => + 'Uverite se da posedujete prava za ovaj podkast pre nego što ga uvezete. Kopiranje i emitovanje podkasta bez odgovarajućih prava je piraterija i podložno je krivičnom gonjenju.', + 'imported_feed_url' => 'URL snabdevača', + 'imported_feed_url_hint' => 'Snabdevač mora biti u xml ili rss formatu.', + 'new_podcast_section_title' => 'Novi podkast', + 'lock_import' => + 'Ovaj snabdevač je zaštićen. Ne možete ga uvesti. Ukoliko ste vlasnik, otključajte snabdevač na originalnoj platformi na kojoj ste ga napravili.', + 'submit' => 'Dodaj uvoz na čekanje', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'čekanje', + 'queued_hint' => 'Zadatak uvoza čeka na obradu.', + 'canceled' => 'otkazano', + 'canceled_hint' => 'Zadatak uvoza je otkazan.', + 'running' => 'u toku', + 'running_hint' => 'Zadatak uvoza se procesuira.', + 'failed' => 'nije uspеlo', + 'failed_hint' => 'Zadatak uvoza nije mogao da se završi: greška skripte.', + 'passed' => 'pauzirano', + 'passed_hint' => 'Zadatak uvoza uspešno obavljen!', + ], + 'feed' => 'Snabdevač', + 'duration' => 'Trajanje uvoza', + 'imported_episodes' => 'Uvežene epizode', + 'imported_episodes_hint' => '{newlyImportedCount} novo uvežena, {alreadyImportedCount} već uveženih.', + 'actions' => [ + 'cancel' => 'Otkaži', + 'retry' => 'Pokušaj ponovo', + 'delete' => 'Obriši', + ], + ], + 'syncForm' => [ + 'title' => 'Sinhronizuj snabdevače', + 'feed_url' => 'URL snabdevača', + 'feed_url_hint' => 'URL veza snabdevača koju želite da sinhronizujete sa trenutnim podkastom.', + 'submit' => 'Dodaj u redosled', + ], + 'messages' => [ + 'canceled' => 'Zadatak uvoza uspešno otkazan!', + 'notRunning' => 'Nije moguće otkazati zadatak uvoza jer isti nije u toku.', + 'alreadyRunning' => 'Zadatak uvoza je u toku. Možete ga otkazati pre ponovnog pokušaja.', + 'retried' => 'Zadatak uvoza je na čekanju, biće pokušan ponovo uskoro!', + 'deleted' => 'Zadatak uvoza uspešno obrisan!', + 'importTaskQueued' => 'Novi zadatak je na čekanju, uvoz će krenuti uskoro!', + 'syncTaskQueued' => 'Novi zadatak uvoza je na čekanju, sinhronizacija će početi uskoro!', + ], +]; diff --git a/modules/PodcastImport/Language/sv/PodcastImport.php b/modules/PodcastImport/Language/sv/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/sv/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/uk/PodcastImport.php b/modules/PodcastImport/Language/uk/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/uk/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PodcastImport/Language/zh-hans/PodcastImport.php b/modules/PodcastImport/Language/zh-hans/PodcastImport.php new file mode 100644 index 00000000..ca714eec --- /dev/null +++ b/modules/PodcastImport/Language/zh-hans/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => '输入', + 'text' => '{podcastTitle} 正在导入中。', + 'cta' => '查看导入状态', + ], + 'old_podcast_section_title' => '要导入的播客', + 'old_podcast_legal_disclaimer_title' => '法律免责声明', + 'old_podcast_legal_disclaimer' => + '请确保您在导入之前拥有此播客的权限。 在没有权限的情况下复制和广播播客是盗版行为,可能受到起诉。', + 'imported_feed_url' => '摘要 URL', + 'imported_feed_url_hint' => '摘要必须是 xml 或 rss 格式。', + 'new_podcast_section_title' => '新播客', + 'lock_import' => + '该摘要受到保护。 您无法导入它。 如果您是所有者,请在源平台解锁。', + 'submit' => '添加导入到队列', + 'queue' => [ + 'status' => [ + 'label' => '状态', + 'queued' => '队列', + 'queued_hint' => '导入任务正在等待处理。', + 'canceled' => '已取消', + 'canceled_hint' => '导入任务已取消。', + 'running' => '运行中', + 'running_hint' => '导入任务正在处理中。', + 'failed' => '已失败', + 'failed_hint' => '导入任务无法完成:脚本失败。', + 'passed' => '已通过', + 'passed_hint' => '导入任务顺利完成!', + ], + 'feed' => '摘要', + 'duration' => '导入时长', + 'imported_episodes' => '导入剧集', + 'imported_episodes_hint' => '{newlyImportedCount} 新导入, {alreadyImportedCount} 已经导入。', + 'actions' => [ + 'cancel' => '取消', + 'retry' => '重试', + 'delete' => '删除', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => '导入任务已成功取消!', + 'notRunning' => '无法取消导入任务,因为它未运行。', + 'alreadyRunning' => '导入任务已在运行。 您可以在重试之前取消它。', + 'retried' => '导入任务已排队,稍后将重试!', + 'deleted' => '导入任务已成功删除!', + 'importTaskQueued' => '新任务已排队,导入即将开始!', + 'syncTaskQueued' => '新的导入任务已排队,即将开始同步!', + ], +]; diff --git a/modules/PodcastImport/Language/zh-hant/PodcastImport.php b/modules/PodcastImport/Language/zh-hant/PodcastImport.php new file mode 100644 index 00000000..cac52509 --- /dev/null +++ b/modules/PodcastImport/Language/zh-hant/PodcastImport.php @@ -0,0 +1,66 @@ + [ + 'disclaimer' => 'Importing', + 'text' => '{podcastTitle} is currently being imported.', + 'cta' => 'See import status', + ], + 'old_podcast_section_title' => 'The podcast to import', + 'old_podcast_legal_disclaimer_title' => 'Legal disclaimer', + 'old_podcast_legal_disclaimer' => + 'Make sure you own the rights for this podcast before importing it. Copying and broadcasting a podcast without the proper rights is piracy and is liable to prosecution.', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => 'The feed must be in xml or rss format.', + 'new_podcast_section_title' => 'The new podcast', + 'lock_import' => + 'This feed is protected. You cannot import it. If you are the owner, unlock it on the origin platform.', + 'submit' => 'Add import to queue', + 'queue' => [ + 'status' => [ + 'label' => 'Status', + 'queued' => 'queued', + 'queued_hint' => 'Import task is awaiting to be processed.', + 'canceled' => 'canceled', + 'canceled_hint' => 'Import task was canceled.', + 'running' => 'running', + 'running_hint' => 'Import task is being processed.', + 'failed' => 'failed', + 'failed_hint' => 'Import task could not complete: script failure.', + 'passed' => 'passed', + 'passed_hint' => 'Import task was completed successfully!', + ], + 'feed' => 'Feed', + 'duration' => 'Import duration', + 'imported_episodes' => 'Imported episodes', + 'imported_episodes_hint' => '{newlyImportedCount} newly imported, {alreadyImportedCount} already imported.', + 'actions' => [ + 'cancel' => 'Cancel', + 'retry' => 'Retry', + 'delete' => 'Delete', + ], + ], + 'syncForm' => [ + 'title' => 'Synchronize feeds', + 'feed_url' => 'Feed URL', + 'feed_url_hint' => 'The feed URL you want to synchronize with the current podcast.', + 'submit' => 'Add to queue', + ], + 'messages' => [ + 'canceled' => 'Import task has been successfully canceled!', + 'notRunning' => 'Cannot cancel Import Task as it is not running.', + 'alreadyRunning' => 'Import Task is already running. You may cancel it before retrying.', + 'retried' => 'Import task has been queued, it will be retried shortly!', + 'deleted' => 'Import task has been successfully deleted!', + 'importTaskQueued' => 'A new task has been queued, import will start shortly!', + 'syncTaskQueued' => 'A new import task has been queued, synchronization will start shortly!', + ], +]; diff --git a/modules/PremiumPodcasts/Config/Registrar.php b/modules/PremiumPodcasts/Config/Registrar.php new file mode 100644 index 00000000..17d66880 --- /dev/null +++ b/modules/PremiumPodcasts/Config/Registrar.php @@ -0,0 +1,22 @@ + + */ + public static function Filters(): array + { + return [ + 'aliases' => [ + 'podcast-unlock' => PodcastUnlockFilter::class, + ], + ]; + } +} diff --git a/modules/PremiumPodcasts/Config/Routes.php b/modules/PremiumPodcasts/Config/Routes.php new file mode 100644 index 00000000..80d19586 --- /dev/null +++ b/modules/PremiumPodcasts/Config/Routes.php @@ -0,0 +1,130 @@ +addPlaceholder('podcastHandle', '[a-zA-Z0-9\_]{1,32}'); + +// Admin routes for subscriptions +$routes->group( + config('Admin') + ->gateway, + [ + 'namespace' => 'Modules\PremiumPodcasts\Controllers', + ], + static function ($routes): void { + $routes->group('podcasts/(:num)/subscriptions', static function ($routes): void { + $routes->get('/', 'SubscriptionController::list/$1', [ + 'as' => 'subscription-list', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ]); + $routes->get('new', 'SubscriptionController::createView/$1', [ + 'as' => 'subscription-create', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ]); + $routes->post( + 'new', + 'SubscriptionController::createAction/$1', + [ + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->post('save-link', 'SubscriptionController::linkSaveAction/$1', [ + 'as' => 'subscription-link-save', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ]); + // Subscription + $routes->group('(:num)', static function ($routes): void { + $routes->get('/', 'SubscriptionController::view/$1/$2', [ + 'as' => 'subscription-view', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ]); + $routes->get( + 'edit', + 'SubscriptionController::editView/$1/$2', + [ + 'as' => 'subscription-edit', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->post( + 'edit', + 'SubscriptionController::editAction/$1/$2', + [ + 'as' => 'subscription-edit', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->get( + 'regenerate-token', + 'SubscriptionController::regenerateToken/$1/$2', + [ + 'as' => 'subscription-regenerate-token', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->get( + 'suspend', + 'SubscriptionController::suspend/$1/$2', + [ + 'as' => 'subscription-suspend', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->post( + 'suspend', + 'SubscriptionController::suspendAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->get( + 'resume', + 'SubscriptionController::resume/$1/$2', + [ + 'as' => 'subscription-resume', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->get( + 'delete', + 'SubscriptionController::delete/$1/$2', + [ + 'as' => 'subscription-delete', + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + $routes->post( + 'delete', + 'SubscriptionController::deleteAction/$1/$2', + [ + 'filter' => 'permission:podcast$1.manage-subscriptions', + ], + ); + }); + }); + }, +); + +$routes->group( + '@(:podcastHandle)', + [ + 'namespace' => 'Modules\PremiumPodcasts\Controllers', + ], + static function ($routes): void { + $routes->get('unlock', 'LockController::index/$1', [ + 'as' => 'premium-podcast-unlock', + ]); + $routes->post('unlock', 'LockController::unlockAction/$1', [ + 'as' => 'premium-podcast-unlock', + ]); + $routes->get('lock', 'LockController::lockAction/$1', [ + 'as' => 'premium-podcast-lock', + ]); + }, +); diff --git a/modules/PremiumPodcasts/Config/Services.php b/modules/PremiumPodcasts/Config/Services.php new file mode 100644 index 00000000..9ca49df7 --- /dev/null +++ b/modules/PremiumPodcasts/Config/Services.php @@ -0,0 +1,28 @@ +setSubscriptionModel($subscriptionModel); + } +} diff --git a/modules/PremiumPodcasts/Controllers/LockController.php b/modules/PremiumPodcasts/Controllers/LockController.php new file mode 100644 index 00000000..b06efd09 --- /dev/null +++ b/modules/PremiumPodcasts/Controllers/LockController.php @@ -0,0 +1,105 @@ +premiumPodcasts = service('premium_podcasts'); + } + + public function _remap(string $method, string ...$params): mixed + { + if ($params === []) { + throw PageNotFoundException::forPageNotFound(); + } + + if (! ($podcast = new PodcastModel()->getPodcastByHandle($params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->podcast = $podcast; + + return $this->{$method}(); + } + + public function index(): RedirectResponse|string + { + if (! $this->podcast->is_premium) { + return redirect()->route('podcast-activity', [$this->podcast->handle]); + } + + $data = [ + 'podcast' => $this->podcast, + ]; + + helper('form'); + + return view('podcast/unlock', $data); + } + + public function unlockAction(): RedirectResponse + { + $rules = [ + 'token' => 'required', + ]; + + if (! $this->validate($rules)) { + return redirect()->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + $token = $validData['token']; + + // attempt unlocking the podcast with the token + if (! $this->premiumPodcasts->unlock($this->podcast->handle, $token)) { + // bad key or subscription is not active + return redirect()->back() + ->withInput() + ->with('error', lang('PremiumPodcasts.messages.unlockBadAttempt')); + } + + $redirectURL = session('redirect_url') ?? site_url('/'); + unset($_SESSION['redirect_url']); + + return redirect() + ->to($redirectURL) + ->withCookies() + ->with('message', lang('PremiumPodcasts.messages.unlockSuccess')); + } + + public function lockAction(): RedirectResponse + { + $this->premiumPodcasts->lock($this->podcast->handle); + + $redirectURL = session('redirect_url') ?? site_url('/'); + unset($_SESSION['redirect_url']); + + return redirect()->to($redirectURL) + ->withCookies() + ->with('message', lang('PremiumPodcasts.messages.lockSuccess')); + } +} diff --git a/modules/PremiumPodcasts/Controllers/SubscriptionController.php b/modules/PremiumPodcasts/Controllers/SubscriptionController.php new file mode 100644 index 00000000..7ddf669a --- /dev/null +++ b/modules/PremiumPodcasts/Controllers/SubscriptionController.php @@ -0,0 +1,462 @@ +getPodcastById((int) $params[0])) instanceof Podcast) { + throw PageNotFoundException::forPageNotFound(); + } + + $this->podcast = $podcast; + + if (count($params) <= 1) { + return $this->{$method}(); + } + + if (! ($this->subscription = new SubscriptionModel()->getSubscriptionById( + (int) $params[1], + )) instanceof Subscription) { + throw PageNotFoundException::forPageNotFound(); + } + + return $this->{$method}(); + } + + public function list(): string + { + $data = [ + 'podcast' => $this->podcast, + ]; + + helper('form'); + + $this->setHtmlHead(lang('Subscription.podcast_subscriptions')); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + ]); + return view('subscription/list', $data); + } + + public function linkSaveAction(): RedirectResponse + { + $rules = [ + 'subscription_link' => 'valid_url_strict|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect()->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $validData = $this->validator->getValidated(); + + if (($subscriptionLink = $validData['subscription_link']) === '') { + service('settings') + ->forget('Subscription.link', 'podcast:' . $this->podcast->id); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.linkRemoveSuccess'), + ); + } + + service('settings') + ->set('Subscription.link', $subscriptionLink, 'podcast:' . $this->podcast->id); + + // clear cached podcast pages to render Call To Action + cache() + ->deleteMatching("page_podcast#{$this->podcast->id}*"); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.linkSaveSuccess'), + ); + } + + public function view(): string + { + $data = [ + 'podcast' => $this->podcast, + 'subscription' => $this->subscription, + ]; + + $this->setHtmlHead(lang('Subscription.view', [$this->subscription->id])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => '#' . $this->subscription->id, + ]); + return view('subscription/view', $data); + } + + public function createView(): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + ]; + + $this->setHtmlHead(lang('Subscription.add', [esc($this->podcast->title)])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + ]); + return view('subscription/create', $data); + } + + public function createAction(): RedirectResponse + { + helper('text'); + + $expiresAt = null; + $expirationDate = $this->request->getPost('expiration_date'); + if ($expirationDate) { + $expiresAt = Time::createFromFormat( + 'Y-m-d H:i', + $expirationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } + + $newSubscription = new Subscription([ + 'podcast_id' => $this->podcast->id, + 'email' => $this->request->getPost('email'), + 'token' => hash('sha256', $rawToken = random_string('alnum', 8)), + 'expires_at' => $expiresAt, + 'created_by' => user_id(), + 'updated_by' => user_id(), + ]); + + $db = db_connect(); + $db->transStart(); + + $subscriptionModel = new SubscriptionModel(); + if (! $subscriptionModel->insert($newSubscription)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $subscriptionModel->errors()); + } + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($newSubscription->email) + ->setSubject(lang('Subscription.emails.welcome_subject', [ + 'podcastTitle' => $this->podcast->title, + ], $this->podcast->language_code)) + ->setMessage(view('subscription/email/welcome', [ + 'subscription' => $newSubscription, + 'token' => $rawToken, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.addError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.addSuccess', [ + 'subscriber' => $newSubscription->email, + ]), + ); + } + + public function regenerateToken(): RedirectResponse + { + helper('text'); + + $this->subscription->token = hash('sha256', $rawToken = random_string('alnum', 8)); + $this->subscription->updated_by = user_id(); + + $db = db_connect(); + + $db->transStart(); + + $subscriptionModel = new SubscriptionModel(); + if (! $subscriptionModel->update($this->subscription->id, $this->subscription)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $subscriptionModel->errors()); + } + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($this->subscription->email) + ->setSubject(lang('Subscription.emails.reset_subject', [], $this->podcast->language_code)) + ->setMessage(view('subscription/email/reset', [ + 'subscription' => $this->subscription, + 'token' => $rawToken, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.regenerateTokenError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.regenerateTokenSuccess', [ + 'subscriber' => $this->subscription->email, + ]), + ); + } + + public function editView(): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + 'subscription' => $this->subscription, + ]; + + $this->setHtmlHead(lang('Subscription.edit', [esc($this->podcast->title)])); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => '#' . $this->subscription->id, + ]); + return view('subscription/edit', $data); + } + + public function editAction(): RedirectResponse + { + $expiresAt = null; + $expirationDate = $this->request->getPost('expiration_date'); + if ($expirationDate) { + $expiresAt = Time::createFromFormat( + 'Y-m-d H:i', + $expirationDate, + $this->request->getPost('client_timezone'), + )->setTimezone(app_timezone()); + } + + $this->subscription->expires_at = $expiresAt; + + $db = db_connect(); + $db->transStart(); + + $subscriptionModel = new SubscriptionModel(); + if (! $subscriptionModel->update($this->subscription->id, $this->subscription)) { + $db->transRollback(); + return redirect() + ->back() + ->withInput() + ->with('errors', $subscriptionModel->errors()); + } + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($this->subscription->email) + ->setSubject(lang('Subscription.emails.edited_subject', [], $this->podcast->language_code)) + ->setMessage(view('subscription/email/edited', [ + 'subscription' => $this->subscription, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.editError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.editSuccess', [ + 'subscriber' => $this->subscription->email, + ]), + ); + } + + public function suspend(): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + 'subscription' => $this->subscription, + ]; + + $this->setHtmlHead(lang('Subscription.suspend')); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => '#' . $this->subscription->id, + ]); + return view('subscription/suspend', $data); + } + + public function suspendAction(): RedirectResponse + { + $db = db_connect(); + $db->transStart(); + + $this->subscription->suspend($this->request->getPost('reason')); + $subscriptionModel = new SubscriptionModel(); + if (! $subscriptionModel->update($this->subscription->id, $this->subscription)) { + return redirect() + ->back() + ->with('errors', $subscriptionModel->errors()); + } + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($this->subscription->email) + ->setSubject(lang('Subscription.emails.suspended_subject', [], $this->podcast->language_code)) + ->setMessage(view('subscription/email/suspended', [ + 'subscription' => $this->subscription, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.suspendError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'messages', + lang('Subscription.messages.suspendSuccess', [ + 'subscriber' => $this->subscription->email, + ]), + ); + } + + public function resume(): RedirectResponse + { + $db = db_connect(); + $db->transStart(); + + $this->subscription->resume(); + + $subscriptionModel = new SubscriptionModel(); + if (! $subscriptionModel->update($this->subscription->id, $this->subscription)) { + return redirect() + ->back() + ->with('errors', $subscriptionModel->errors()); + } + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($this->subscription->email) + ->setSubject(lang('Subscription.emails.resumed_subject', [], $this->podcast->language_code)) + ->setMessage(view('subscription/email/resumed', [ + 'subscription' => $this->subscription, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.resumeError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'message', + lang('Subscription.messages.resumeSuccess', [ + 'subscriber' => $this->subscription->email, + ]), + ); + } + + public function delete(): string + { + helper('form'); + + $data = [ + 'podcast' => $this->podcast, + 'subscription' => $this->subscription, + ]; + + $this->setHtmlHead(lang('Subscription.delete')); + replace_breadcrumb_params([ + 0 => $this->podcast->at_handle, + 1 => '#' . $this->subscription->id, + ]); + return view('subscription/delete', $data); + } + + public function deleteAction(): RedirectResponse + { + $db = db_connect(); + $db->transStart(); + + new SubscriptionModel() + ->delete($this->subscription->id); + + /** @var Email $email */ + $email = service('email'); + + if (! $email->setTo($this->subscription->email) + ->setSubject(lang('Subscription.emails.deleted_subject', [], $this->podcast->language_code)) + ->setMessage(view('subscription/email/deleted', [ + 'subscription' => $this->subscription, + ]))->setMailType('html') + ->send()) { + $db->transRollback(); + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'errors', + [lang('Subscription.messages.deleteError'), $email->printDebugger([])], + ); + } + + $db->transComplete(); + + return redirect()->route('subscription-list', [$this->podcast->id])->with( + 'messages', + lang('Subscription.messages.deleteSuccess', [ + 'subscriber' => $this->subscription->email, + ]), + ); + } +} diff --git a/modules/PremiumPodcasts/Database/Migrations/2022-07-07-120000_add_subscriptions.php b/modules/PremiumPodcasts/Database/Migrations/2022-07-07-120000_add_subscriptions.php new file mode 100644 index 00000000..57fa8dfd --- /dev/null +++ b/modules/PremiumPodcasts/Database/Migrations/2022-07-07-120000_add_subscriptions.php @@ -0,0 +1,83 @@ +forge->addField([ + 'id' => [ + 'type' => 'INT', + 'unsigned' => true, + 'auto_increment' => true, + ], + 'podcast_id' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'email' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + 'token' => [ + 'type' => 'VARCHAR', + 'constraint' => 64, + ], + 'status' => [ + 'type' => 'ENUM', + 'constraint' => ['active', 'suspended'], + 'default' => 'active', + ], + 'status_message' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => true, + ], + 'expires_at' => [ + 'type' => 'DATETIME', + 'null' => true, + ], + 'created_by' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'updated_by' => [ + 'type' => 'INT', + 'unsigned' => true, + ], + 'created_at' => [ + 'type' => 'DATETIME', + ], + 'updated_at' => [ + 'type' => 'DATETIME', + ], + ]); + + $this->forge->addKey('id', true); + $this->forge->addUniqueKey(['podcast_id', 'email']); + $this->forge->addUniqueKey('token'); + $this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE'); + $this->forge->addForeignKey('created_by', 'users', 'id'); + $this->forge->addForeignKey('updated_by', 'users', 'id'); + $this->forge->createTable('subscriptions'); + } + + #[Override] + public function down(): void + { + $this->forge->dropTable('subscriptions'); + } +} diff --git a/modules/PremiumPodcasts/Entities/Subscription.php b/modules/PremiumPodcasts/Entities/Subscription.php new file mode 100644 index 00000000..aa8e32be --- /dev/null +++ b/modules/PremiumPodcasts/Entities/Subscription.php @@ -0,0 +1,115 @@ + + */ + protected $dates = ['expires_at', 'created_at', 'updated_at']; + + /** + * @var array + */ + protected $casts = [ + 'id' => 'integer', + 'podcast_id' => 'integer', + 'email' => 'string', + 'token' => 'string', + 'status' => 'string', + 'status_message' => '?string', + 'created_by' => 'integer', + 'updated_by' => 'integer', + ]; + + public function getStatus(): string + { + return $this->expires_at->isBefore(Time::now()) ? 'expired' : $this->attributes['status']; + } + + /** + * Suspend a subscription. + * + * @return $this + */ + public function suspend(string $reason): static + { + $this->attributes['status'] = 'suspended'; + $this->attributes['status_message'] = $reason; + + return $this; + } + + /** + * Resumes a subscription / unSuspend. + * + * @return $this + */ + public function resume(): static + { + $this->attributes['status'] = 'active'; + $this->attributes['status_message'] = null; + + return $this; + } + + /** + * Checks to see if a subscription has been suspended. + */ + public function isSuspended(): bool + { + return isset($this->attributes['status']) && $this->attributes['status'] === 'suspended'; + } + + /** + * Returns the subscription's podcast + */ + public function getPodcast(): ?Podcast + { + if (! $this->podcast instanceof Podcast) { + $this->podcast = new PodcastModel() + ->getPodcastById($this->podcast_id); + } + + return $this->podcast; + } + + public function getDownloadsLast3Months(): int + { + return new AnalyticsPodcastBySubscriptionModel() + ->getNumberOfDownloadsLast3Months($this->podcast_id, $this->id); + } +} diff --git a/modules/PremiumPodcasts/Filters/PodcastUnlockFilter.php b/modules/PremiumPodcasts/Filters/PodcastUnlockFilter.php new file mode 100644 index 00000000..2f08a68b --- /dev/null +++ b/modules/PremiumPodcasts/Filters/PodcastUnlockFilter.php @@ -0,0 +1,95 @@ +params(); + + if ($routerParams === []) { + return null; + } + + // no need to go through the unlock form if user is connected + if (auth()->loggedIn()) { + return null; + } + + // Make sure this isn't already a premium podcast route + if (url_is((string) route_to('premium-podcast-unlock', $routerParams[0]))) { + return null; + } + + // expect 2 parameters (podcast handle and episode slug) + if (count($routerParams) < 2) { + return null; + } + + $episode = new EpisodeModel() + ->getEpisodeBySlug($routerParams[0], $routerParams[1]); + + if (! $episode instanceof Episode) { + return null; + } + + // Make sure that public episodes are still accessible + if (! $episode->is_premium) { + return null; + } + + // Episode should be embeddable even if it is premium + if (url_is((string) route_to('embed', $episode->podcast->handle, $episode->slug))) { + return null; + } + + /** @var PremiumPodcasts $premiumPodcasts */ + $premiumPodcasts = service('premium_podcasts'); + if ($premiumPodcasts->check($routerParams[0])) { + return null; + } + + // podcast is locked, send to the unlock form + session() + ->set('redirect_url', current_url()); + + return redirect()->route('premium-podcast-unlock', [$routerParams[0]]); + } + + /** + * @param list|null $arguments + * + * @return ResponseInterface|null + */ + #[Override] + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + return null; + } +} diff --git a/modules/PremiumPodcasts/Helpers/premium_podcasts_helper.php b/modules/PremiumPodcasts/Helpers/premium_podcasts_helper.php new file mode 100644 index 00000000..46794c85 --- /dev/null +++ b/modules/PremiumPodcasts/Helpers/premium_podcasts_helper.php @@ -0,0 +1,35 @@ +check($podcastHandle); + } +} + +if (! function_exists('subscription')) { + /** + * Returns the Subscription instance for the currently active subscription. + */ + function subscription(string $podcastHandle): ?Subscription + { + /** @var PremiumPodcasts $premiumPodcast */ + $premiumPodcast = service('premium_podcasts'); + $premiumPodcast->check($podcastHandle); + + return $premiumPodcast->subscription($podcastHandle); + } +} diff --git a/modules/PremiumPodcasts/Language/ar/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ar/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ar/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ar/Subscription.php b/modules/PremiumPodcasts/Language/ar/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ar/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/br/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/br/PremiumPodcasts.php new file mode 100644 index 00000000..42e897b6 --- /dev/null +++ b/modules/PremiumPodcasts/Language/br/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Rannoù Premium a zo er podkast-mañ', + 'episode_is_premium' => 'Ur rann Premium eo, ne c\'hell bezañ gwelet nemet gant koumananterien·ezed Premium', + 'unlock_episode' => 'Evit koumananterien·ezed Premium eo ar rann-mañ. Klikit evit dibrennañ anezhi!', + 'banner_unlock' => 'Rannoù Premium a zo er podkast-mañ, ne c\'hellont bezañ gwelet nemet gant koumananterien·ezed Premium.', + 'banner_lock' => 'Dibrennet eo bet ar podkast. Plijadur deoc\'h gant ar rannoù Premium!', + 'subscribe' => 'Koumanantiñ', + 'lock' => 'Prennañ', + 'unlock' => 'Dibrennañ', + 'unlock_form' => [ + 'title' => 'Endalc\'had Premium', + 'subtitle' => 'Rannoù Premium prennet zo er podkast-mañ. Ha ganeoc\'h emañ an alc\'hwez evit dibrennañ anezho?', + 'token' => 'Lakait hoc’h alc\'hwez', + 'token_hint' => 'Ma\'z oc\'h koumanantet ouzh {podcastTitle} e c\'hellit eilañ an alc’hwez a zo bet kaset deoc\'h dre bostel ha pegañ anezhañ amañ.', + 'submit' => 'Dibrennañ an holl rannoù!', + 'call_to_action' => 'Dibrennit holl rannoù {podcastTitle}:', + 'subscribe_cta' => 'Koumanantit bremañ!', + ], + 'messages' => [ + 'unlockSuccess' => 'Dibrennet eo bet ar podkast gant berzh! Plijadur deoc\'h gant ar rannoù Premium!', + 'unlockBadAttempt' => 'Hoc\'h alc\'hwez n\'eo seblant ket bezañ mat…', + 'lockSuccess' => 'Dibrennet eo bet ar podkast gant berzh!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/br/Subscription.php b/modules/PremiumPodcasts/Language/br/Subscription.php new file mode 100644 index 00000000..a956f60b --- /dev/null +++ b/modules/PremiumPodcasts/Language/br/Subscription.php @@ -0,0 +1,100 @@ + 'Koumanantoù ar podkast', + 'add' => 'Koumanant nevez', + 'view' => 'Gwelet ar c\'houmanant', + 'edit' => 'Kemmañ ar c\'houmanant', + 'regenerate_token' => 'Azgenel ar jedouer', + 'suspend' => 'Ehanañ ar c\'houmanant', + 'resume' => 'Adkregiñ gant ar c\'houmanant', + 'delete' => 'Dilemel ar c\'houmanant', + 'status' => [ + 'active' => 'Bev', + 'suspended' => 'Ehanet', + 'expired' => 'Tremenet', + ], + 'list' => [ + 'number' => 'Niverenn', + 'email' => 'Postel', + 'expiration_date' => 'Deiziad termen', + 'unlimited' => 'Didermen', + 'downloads' => 'Pellgargadennoù', + 'status' => 'Statud', + ], + 'form' => [ + 'email' => 'Postel', + 'expiration_date' => 'Deiziad termen', + 'expiration_date_hint' => 'An deiziad hag an eur ma vo tremenet ar c\'houmanant. Laoskit goullo evit ur c\'houmanant didermen.', + 'submit_create' => 'Krouiñ ur c\'houmanant', + 'submit_edit' => 'Kemmañ ar c\'houmanant', + ], + 'form_link_add' => [ + 'link' => 'Liamm etrezek pajenn ar c\'houmanant', + 'link_hint' => 'Gant an dra-se e vo ouzhpennet d\'al lec\'hienn ur galv da ober evit pediñ ar selaouerien·ezed da goumanantiñ ouzh ar podkast.', + 'submit' => 'Enrollañ al liamm', + ], + 'suspend_form' => [ + 'disclaimer' => 'Ehanañ ar c\'houmanant a viro ouzh ar goumananterien·ezed da welet an endalc\'had Premium. Gallout a reoc\'h skarzhañ an ehan war-lerc\'h.', + 'reason' => 'Abeg', + 'reason_placeholder' => 'Perak ho peus c\'hoant da ehanañ ar c\'houmanant?', + "submit" => 'Ehanañ ar c\'houmanant', + ], + 'delete_form' => [ + 'disclaimer' => 'Dilemel koumanant {subscriber} a skarzho an holl stadegoù stag outañ.', + 'understand' => 'Kompren a ran, dilemel ar c\'houmanant da vat', + 'submit' => 'Dilemel ar c\'houmanant', + ], + 'messages' => [ + 'addSuccess' => 'Ur c\'houmanant nevez zo bet ouzhpennet! Ur postel evit degemer {subscriber} zo bet kaset.', + 'addError' => 'N\'eo ket bet ouzhpennet ar c\'houmanant.', + 'editSuccess' => 'Deiziad termen ar c\'houmanant zo bet nevesaet! Ur postel zo bet kaset da {subscriber}.', + 'editError' => 'N\'eo ket bet kemmet ar c\'houmanant.', + 'regenerateTokenSuccess' => 'Azganet eo bet ar jedouer! Kaset eo bet ar jedouer nevez da {subscriber} dre bostel.', + 'regenerateTokenError' => 'N\'eo ket bet gellet azgenel ar jedouer.', + 'deleteSuccess' => 'Dilamet eo bet ar c\'houmanant! Ur postel zo bet kaset da {subscriber}.', + 'deleteError' => 'N\'eo ket bet gellet dilemel ar c\'houmanant.', + 'suspendSuccess' => 'Ehanet eo bet ar c\'houmanant! Ur postel zo bet kaset da {subscriber}.', + 'suspendError' => 'N\'eo ket bet gellet ehanañ ar c\'houmanant.', + 'resumeSuccess' => 'Adkroget eo bet gant ar c\'houmanant! Ur postel zo bet kaset da {subscriber}.', + 'resumeError' => 'N\'eo ket bet gellet adkregiñ gant ar c\'houmanant.', + 'linkSaveSuccess' => 'Liamm ar c\'houmanant zo bet enrollet gant berzh! Diskouezet e vo war al lec\'hienn evel ur galv da ober!', + 'linkRemoveSuccess' => 'Dilamet eo bet liamm ar c\'houmanant gant berzh!', + ], + 'emails' => [ + 'greeting' => 'Ata,', + 'token' => 'Ho jedouer: {0}', + 'unique_feed_link' => 'Liamm ho kwazh deoc\'h-c\'hwi: {0}', + 'how_to_use' => 'Penaos ober gantañ?', + 'two_ways' => 'Daou zoare zo evit dibrennañ rannoù Premium:', + 'import_into_app' => 'Eilit liamm ho kwazh personelaet e-barzh hoc\'h arload podkast karetañ (enporzhiit anezhañ evel ur wazh prevez kuit da lakaat war wel ho titouroù).', + 'go_to_website' => 'Kit da lec\'hienn {podcastWebsite} ha dibrennit ar podkast gant ho jedouer.', + 'welcome_subject' => 'Degemer mat war {podcastTitle}', + 'welcome' => 'Koumanantet oc\'h ouzh {podcastTitle}, mersi bras deoc\'h ha degemer mat!', + 'welcome_token_title' => 'Setu an titouroù evit dibrennañ rannoù Premium ar podkast:', + 'welcome_expires' => 'Arventennet eo bet ho koumanant da echuiñ d\'an/ar {0}.', + 'welcome_never_expires' => 'Arventennet eo bet ho koumanant evit bezañ didermen.', + 'reset_subject' => 'Azganet eo bet ho jedouer!', + 'reset_token' => 'Adderaouekaet eo bet ho moned da {podcastTitle}!', + 'reset_token_title' => 'Titouroù nevez zo bet ganet evit ma tibrennfec’h rannoù Premium ar podkast:', + 'edited_subject' => 'Nevesaet eo bet ho koumanant!', + 'edited_expires' => 'Arventennet eo bet ho koumanant ouzh {podcastTitle} da echuiñ d\'an/ar {expiresAt}.', + 'edited_never_expires' => 'Arventennet eo bet ho koumanant ouzh {podcastTitle} da vezañ didermen!', + 'suspended_subject' => 'Ehanet eo bet ho koumanant!', + 'suspended' => 'Ehanet eo bet ho koumanant ouzh {podcastTitle}! Ne c\'hallit ket gwelet rannoù Premium ar podkast ken.', + 'suspended_reason' => 'Evit an abeg da-heul: {0}', + 'resumed_subject' => 'Adkrog eo ho koumanant!', + 'resumed' => 'Adkrog eo ho koumanant ouzh {podcastTitle}! Gallout a rit ket gwelet rannoù Premium ar podkast en-dro.', + 'deleted_subject' => 'Dilamet eo bet ho koumanant!', + 'deleted' => 'Dilamet eo bet ho koumanant ouzh {podcastTitle}! Ne c\'hallit ket gwelet rannoù Premium ar podkast ken.', + 'footer' => '{castopod} herberc\'hiet war {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ca/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ca/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ca/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ca/Subscription.php b/modules/PremiumPodcasts/Language/ca/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ca/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/da/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/da/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/da/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/da/Subscription.php b/modules/PremiumPodcasts/Language/da/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/da/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/de/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/de/PremiumPodcasts.php new file mode 100644 index 00000000..178640ed --- /dev/null +++ b/modules/PremiumPodcasts/Language/de/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast enthält Premium-Episoden', + 'episode_is_premium' => 'Diese Episode ist nur verfügbar für Premium-Abonnenten', + 'unlock_episode' => 'Diese Episode ist nur für Premium-Abonnenten. Klicke, um sie freizuschalten!', + 'banner_unlock' => 'Dieser Podcast enthält Premium-Episoden, nur verfügbar für Premium-Abonnenten.', + 'banner_lock' => 'Der Podcast ist freigeschaltet, viel Spaß mit den Premium-Episoden!', + 'subscribe' => 'Abonnieren', + 'lock' => 'Sperren', + 'unlock' => 'Entsperren', + 'unlock_form' => [ + 'title' => 'Premium-Inhalt', + 'subtitle' => 'Dieser Podcast enthält gesperrte Premium-Episoden! Haben Sie einen Schlüssel, um diese freizuschalten?', + 'token' => 'Geben Sie Ihren Schlüssel ein', + 'token_hint' => 'Wenn Sie {podcastTitle} abonniert haben, können Sie hier den Schlüssel einfügen, den Sie per E-Mail erhalten haben.', + 'submit' => 'Alle Episoden freischalten!', + 'call_to_action' => 'Schalten Sie alle Episoden von {podcastTitle} frei:', + 'subscribe_cta' => 'Jetzt abonnieren!', + ], + 'messages' => [ + 'unlockSuccess' => 'Der Podcast wurde erfolgreich entsperrt! Viel Spaß mit den Premium-Episoden!', + 'unlockBadAttempt' => 'Ihr Schlüssel scheint nicht zu funktionieren…', + 'lockSuccess' => 'Der Podcast wurde erfolgreich gesperrt!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/de/Subscription.php b/modules/PremiumPodcasts/Language/de/Subscription.php new file mode 100644 index 00000000..67b91013 --- /dev/null +++ b/modules/PremiumPodcasts/Language/de/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast-Abonnements', + 'add' => 'Neues Abonnement', + 'view' => 'Abonnement anzeigen', + 'edit' => 'Abonnement bearbeiten', + 'regenerate_token' => 'Token neu generieren', + 'suspend' => 'Abonnement unterbrechen', + 'resume' => 'Abonnement fortsetzen', + 'delete' => 'Abonnement löschen', + 'status' => [ + 'active' => 'Aktiv', + 'suspended' => 'Unterbrochen', + 'expired' => 'Abgelaufen', + ], + 'list' => [ + 'number' => 'Nummer', + 'email' => 'E-Mail', + 'expiration_date' => 'Ablaufdatum', + 'unlimited' => 'Unbegrenzt', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'E-Mail', + 'expiration_date' => 'Ablaufdatum', + 'expiration_date_hint' => 'Das Datum und die Uhrzeit, zu der das Abonnement abläuft. Leer lassen für ein unbegrenztes Abonnement.', + 'submit_create' => 'Abonnement einrichten', + 'submit_edit' => 'Abonnement bearbeiten', + ], + 'form_link_add' => [ + 'link' => 'Link zur Abonnement-Seite', + 'link_hint' => 'Dies fügt einen CTA (Call to Action) zur Webseite hinzu, der Hörer dazu einlädt, den Podcast zu abonnieren.', + 'submit' => 'Link speichern', + ], + 'suspend_form' => [ + 'disclaimer' => 'Das Pausieren des Abonnements wird dem Abonnenten den Zugang zu den Premium-Inhalten einschränken. Sie können die Pausierung jederzeit wieder aufheben.', + 'reason' => 'Grund', + 'reason_placeholder' => 'Warum unterbrechen Sie Ihr Abonnement?', + "submit" => 'Abonnement unterbrechen', + ], + 'delete_form' => [ + 'disclaimer' => 'Durch das Löschen des Abonnements von {subscriber} werden alle damit verbundenen Analysedaten entfernt.', + 'understand' => 'Ich verstehe, entferne das Abonnement dauerhaft', + 'submit' => 'Abonnement entfernen', + ], + 'messages' => [ + 'addSuccess' => 'Neues Abonnement hinzugefügt! Eine Willkommens-E-Mail wurde an {subscriber} gesendet.', + 'addError' => 'Abonnement konnte nicht hinzugefügt werden.', + 'editSuccess' => 'Das Ablaufdatum des Abonnements wurde aktualisiert! Es wurde eine E-Mail an {subscriber} gesendet.', + 'editError' => 'Abonnement konnte nicht bearbeitet werden.', + 'regenerateTokenSuccess' => 'Der Schlüssel wurde neu generiert! Eine E-Mail mit dem neuen Schlüssel wurde an {subscriber} gesendet.', + 'regenerateTokenError' => 'Schlüssel konnte nicht neu generiert werden.', + 'deleteSuccess' => 'Das Abonnement wurde entfernt! Es wurde eine E-Mail an {subscriber} gesendet.', + 'deleteError' => 'Abonnement konnte nicht entfernt werden.', + 'suspendSuccess' => 'Das Abonnement wurde pausiert! Es wurde eine E-Mail an {subscriber} gesendet.', + 'suspendError' => 'Abonnement konnte nicht pausiert werden.', + 'resumeSuccess' => 'Das Abonnement wurde fortgesetzt! Es wurde eine E-Mail an {subscriber} gesendet.', + 'resumeError' => 'Abonnement konnte nicht fortgesetzt werden.', + 'linkSaveSuccess' => 'Der Abonnement-Link wurde erfolgreich gespeichert! Dieser wird als CTA (Call to Action) auf der Webseite erscheinen!', + 'linkRemoveSuccess' => 'Der Abonnement-Link wurde erfolgreich entfernt!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Ihr Token: {0}', + 'unique_feed_link' => 'Ihr eindeutiger Feed-Link: {0}', + 'how_to_use' => 'Wie nutzt man es?', + 'two_ways' => 'Sie haben zwei Möglichkeiten, die Premium-Episoden freizuschalten:', + 'import_into_app' => 'Kopieren Sie Ihre einmalige Feed-URL in Ihre Lieblings-Podcast-App (importieren sie diesen als privaten Feed, um Ihre Anmeldedaten geheim zu halten).', + 'go_to_website' => 'Gehen Sie zu der Webseite von {podcastWebsite} und entsperren Sie den Podcast mit Ihrem Schlüssel.', + 'welcome_subject' => 'Willkommen bei {podcastTitle}', + 'welcome' => 'Sie haben {podcastTitle} abonniert, vielen Dank und herzlich willkommen!', + 'welcome_token_title' => 'Hier sind Ihre Anmeldedaten, um die Premium-Episoden des Podcasts freizuschalten:', + 'welcome_expires' => 'Ihr Abonnement läuft am {0} ab.', + 'welcome_never_expires' => 'Ihr Abonnement läuft nicht ab.', + 'reset_subject' => 'Ihr Schlüssel wurde zurückgesetzt!', + 'reset_token' => 'Ihr Zugriff auf {podcastTitle} wurde zurückgesetzt!', + 'reset_token_title' => 'Es wurden neue Anmeldedaten generiert, um die Premium-Episoden des Podcasts freizuschalten:', + 'edited_subject' => 'Ihr Abonnement wurde aktualisiert!', + 'edited_expires' => 'Ihr Abonnement für {podcastTitle} läuft am {expiresAt} ab.', + 'edited_never_expires' => 'Ihr Abonnement für {podcastTitle} läuft nie ab!', + 'suspended_subject' => 'Ihr Abonnement wurde pausiert!', + 'suspended' => 'Ihr Abonnement für {podcastTitle} wurde pausiert! Sie können nun nicht mehr auf die Premium-Episoden des Podcasts zugreifen.', + 'suspended_reason' => 'Das ist aus dem folgenden Grund: {0}', + 'resumed_subject' => 'Ihr Abonnement wurde wieder aufgenommen!', + 'resumed' => 'Ihr Abonnement für {podcastTitle} wurde fortgesetzt! Sie können nun wieder auf die Premium-Episoden des Podcasts zugreifen.', + 'deleted_subject' => 'Ihr Abonnement wurde entfernt!', + 'deleted' => 'Ihr Abonnement für {podcastTitle} wurde entfernt! Sie können nun nicht mehr auf die Premium-Episoden des Podcasts zugreifen.', + 'footer' => '{castopod} betrieben auf {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/el/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/el/PremiumPodcasts.php new file mode 100644 index 00000000..2cdc8702 --- /dev/null +++ b/modules/PremiumPodcasts/Language/el/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Το Podcast περιέχει premium επεισόδια', + 'episode_is_premium' => 'Το επεισόδιο είναι premium, μόνο διαθέσιμο σε συνδρομητές premium', + 'unlock_episode' => 'Αυτό το επεισόδιο είναι μόνο για premium συνδρομητές. Κάντε κλικ για να το ξεκλειδώσετε!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Το Podcast είναι ξεκλειδωμένο, απολαύστε τα premium επεισόδια!', + 'subscribe' => 'Συνδρομή', + 'lock' => 'Κλείδωμα', + 'unlock' => 'Ξεκλείδωμα', + 'unlock_form' => [ + 'title' => 'Premium περιεχόμενο', + 'subtitle' => 'Αυτό το podcast περιέχει κλειδωμένα premium επεισόδια! Έχεις το κλειδί για να τα ξεκλειδώσεις;', + 'token' => 'Δώστε το κλειδί', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Ξεκλείδωμα όλων των επεισοδίων!', + 'call_to_action' => 'Ξεκλειδώστε όλα τα επεισόδια του {podcastTitle}:', + 'subscribe_cta' => 'Εγγραφείτε τώρα!', + ], + 'messages' => [ + 'unlockSuccess' => 'Το Podcast ξεκλειδώθηκε με επιτυχία! Απολαύστε τα premium επεισόδια!', + 'unlockBadAttempt' => 'Το κλειδί σας δεν φαίνεται να λειτουργεί…', + 'lockSuccess' => 'Το Podcast κλειδώθηκε με επιτυχία!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/el/Subscription.php b/modules/PremiumPodcasts/Language/el/Subscription.php new file mode 100644 index 00000000..a8f8f923 --- /dev/null +++ b/modules/PremiumPodcasts/Language/el/Subscription.php @@ -0,0 +1,100 @@ + 'Συνδρομές Podcast', + 'add' => 'Νέα συνδρομή', + 'view' => 'Προβολή συνδρομής', + 'edit' => 'Τροποποίηση συνδρομής', + 'regenerate_token' => 'Αναδημιουργία token', + 'suspend' => 'Αναστολή συνδρομής', + 'resume' => 'Συνέχιση συνδρομής', + 'delete' => 'Διαγραφή συνδρομής', + 'status' => [ + 'active' => 'Ενεργή', + 'suspended' => 'Έχει ανασταλεί', + 'expired' => 'Έληξε', + ], + 'list' => [ + 'number' => 'Αριθμός', + 'email' => 'Ηλεκτρονική διεύθυνση', + 'expiration_date' => 'Ημερομηνία λήξης', + 'unlimited' => 'Απεριόριστα', + 'downloads' => 'Λήψεις', + 'status' => 'Κατάσταση', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Ημερομηνία λήξης', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/en/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/en/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/en/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/en/Subscription.php b/modules/PremiumPodcasts/Language/en/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/en/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/es/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/es/PremiumPodcasts.php new file mode 100644 index 00000000..e7beaae7 --- /dev/null +++ b/modules/PremiumPodcasts/Language/es/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contiene episodios premium', + 'episode_is_premium' => 'El episodio es premium, sólo disponible para los suscriptores premium', + 'unlock_episode' => 'Este episodio es sólo para suscriptores premium. ¡Haz clic para desbloquearlo!', + 'banner_unlock' => 'Este podcast contiene episodios premium, sólo disponible para los suscriptores premium.', + 'banner_lock' => 'Podcast desbloqueado, ¡disfruta de los episodios premium!', + 'subscribe' => 'Suscríbete', + 'lock' => 'Bloquear', + 'unlock' => 'Desbloquear', + 'unlock_form' => [ + 'title' => 'Contenido premium', + 'subtitle' => '¡Este podcast contiene episodios premium bloqueados! ¿Tienes la clave para desbloquearlos?', + 'token' => 'Introduzca su clave', + 'token_hint' => 'Si está suscrito a {podcastTitle}, puede copiar la clave que le fue enviada por correo electrónico y pegarla aquí.', + 'submit' => '¡Desbloquea todos los episodios!', + 'call_to_action' => 'Desbloquea todos los episodios de {podcastTitle}:', + 'subscribe_cta' => '¡Suscríbete ahora!', + ], + 'messages' => [ + 'unlockSuccess' => '¡Podcast desbloqueado con éxito! ¡Disfruta de los episodios premium!', + 'unlockBadAttempt' => 'Parece que tu clave no está funcionando…', + 'lockSuccess' => 'El Podcast fue bloqueado con éxito!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/es/Subscription.php b/modules/PremiumPodcasts/Language/es/Subscription.php new file mode 100644 index 00000000..76df4e21 --- /dev/null +++ b/modules/PremiumPodcasts/Language/es/Subscription.php @@ -0,0 +1,100 @@ + 'Suscripciones de Podcast', + 'add' => 'Nueva suscripción', + 'view' => 'Ver suscripción', + 'edit' => 'Editar la suscripción', + 'regenerate_token' => 'Regenerar token', + 'suspend' => 'Suspender suscripción', + 'resume' => 'Reanudar suscripción', + 'delete' => 'Eliminar suscripción', + 'status' => [ + 'active' => 'Activo', + 'suspended' => 'Suspendido', + 'expired' => 'Caducado', + ], + 'list' => [ + 'number' => 'Número', + 'email' => 'Correo electrónico', + 'expiration_date' => 'Fecha de expiración', + 'unlimited' => 'Ilimitado', + 'downloads' => 'Descargas', + 'status' => 'Estado', + ], + 'form' => [ + 'email' => 'Correo electrónico', + 'expiration_date' => 'Fecha de expiración', + 'expiration_date_hint' => 'La fecha y hora en que caduca la suscripción. Dejar en blanco para una suscripción ilimitada.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Editar la suscripción', + ], + 'form_link_add' => [ + 'link' => 'Enlace de página de suscripción', + 'link_hint' => 'Esto añadirá una llamada a la acción en el sitio web invitando a los oyentes a suscribirse al podcast.', + 'submit' => 'Guardar enlace', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspender la suscripción restringirá que el suscriptor tenga acceso al contenido premium. Aún podrá levantar la suspensión después.', + 'reason' => 'Motivo', + 'reason_placeholder' => '¿Por qué quieres detener tu suscripción?', + "submit" => 'Suspender suscripción', + ], + 'delete_form' => [ + 'disclaimer' => 'Eliminar la suscripción de {subscriber} eliminará todos los datos analíticos asociados a ella.', + 'understand' => 'Entiendo, eliminar la suscripción permanentemente', + 'submit' => 'Eliminar Suscripción', + ], + 'messages' => [ + 'addSuccess' => '¡Nueva suscripción añadida! Se ha enviado un correo electrónico de bienvenida a {subscriber}.', + 'addError' => 'La suscripción no pudo ser añadida.', + 'editSuccess' => '¡La fecha de caducidad de la suscripción ha sido actualizada! Se ha enviado un correo electrónico a {subscriber}.', + 'editError' => 'No se pudo editar la suscripción.', + 'regenerateTokenSuccess' => '¡Token regenerado! Un correo electrónico fue enviado a {subscriber} con el nuevo token.', + 'regenerateTokenError' => 'El token no se pudo regenerar.', + 'deleteSuccess' => '¡La suscripción ha sido eliminada! Se ha enviado un correo electrónico a {subscriber}.', + 'deleteError' => 'La suscripción no pudo ser eliminada.', + 'suspendSuccess' => '¡La suscripción ha sido suspendida! Se ha enviado un correo electrónico a {subscriber}.', + 'suspendError' => 'La suscripción no pudo ser suspendida.', + 'resumeSuccess' => 'La suscripción se ha reanudado! Se ha enviado un correo electrónico a {subscriber}.', + 'resumeError' => 'No se pudo reanudar la suscripción.', + 'linkSaveSuccess' => '¡El enlace de suscripción se ha guardado correctamente! ¡Aparecerá en el sitio web como una acción de llamada!', + 'linkRemoveSuccess' => '¡El enlace de suscripción se eliminó correctamente!', + ], + 'emails' => [ + 'greeting' => 'Hola,', + 'token' => 'Tu token: {0}', + 'unique_feed_link' => 'Tu enlace de feed único: {0}', + 'how_to_use' => '¿Cómo se usa?', + 'two_ways' => 'Tienes dos maneras de desbloquear los episodios premium:', + 'import_into_app' => 'Copie su Url única dentro de su aplicación de podcast favorita (importe como un feed privado para evitar exponer sus credenciales).', + 'go_to_website' => 'Ve a la página web de {podcastWebsite} y desbloquea el podcast con tu token.', + 'welcome_subject' => 'Bienvenido a {podcastTitle}', + 'welcome' => 'Te has suscrito a {podcastTitle}, ¡gracias y bienvenido!', + 'welcome_token_title' => 'Aquí están tus credenciales para desbloquear los episodios premium del podcast:', + 'welcome_expires' => 'Sus suscripción caducará en {0}.', + 'welcome_never_expires' => 'Tu suscripción nunca expirará.', + 'reset_subject' => '¡Tu token ha sido restablecido!', + 'reset_token' => '¡Tu acceso a {podcastTitle} ha sido restablecido!', + 'reset_token_title' => 'Se han generado nuevas credenciales para desbloquear los episodios premium del podcast:', + 'edited_subject' => 'Su suscripción ha sido actualizada!', + 'edited_expires' => 'Su suscripción para {podcastTitle} caducará el {expiresAt}.', + 'edited_never_expires' => '¡Tu suscripción para {podcastTitle} nunca caducará!', + 'suspended_subject' => 'Tu suscripción ha sido suspendida!', + 'suspended' => '¡Tu suscripción para {podcastTitle} ha sido suspendida! Ya no puedes acceder a los episodios premium del podcast.', + 'suspended_reason' => 'Este es el siguiente motivo: {0}', + 'resumed_subject' => 'Hemos reactivado tu suscripción!', + 'resumed' => '¡Tu suscripción para {podcastTitle} ha sido reanudada! Puedes acceder de nuevo a los episodios premium del podcast.', + 'deleted_subject' => 'La suscripción ha sido eliminada!', + 'deleted' => '¡Tu suscripción para {podcastTitle} ha sido eliminada! Ya no tienes acceso a los episodios premium del podcast.', + 'footer' => '{castopod} alojado en {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/eu/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/eu/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/eu/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/eu/Subscription.php b/modules/PremiumPodcasts/Language/eu/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/eu/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fa/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/fa/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/fa/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fa/Subscription.php b/modules/PremiumPodcasts/Language/fa/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/fa/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr-ca/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/fr-ca/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr-ca/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr-ca/Subscription.php b/modules/PremiumPodcasts/Language/fr-ca/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr-ca/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/fr/PremiumPodcasts.php new file mode 100644 index 00000000..007b90bd --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Le Podcast contient des épisodes premium', + 'episode_is_premium' => 'Cet épisode est premium, uniquement disponible pour les abonnés premium', + 'unlock_episode' => 'Cet épisode est réservé aux abonnés premium. Cliquez pour le débloquer !', + 'banner_unlock' => 'Ce podcast contient des épisodes premium, uniquement disponibles pour les abonnés premium.', + 'banner_lock' => 'Podcast débloqué avec succès ! Profitez des épisodes premium !', + 'subscribe' => 'S\'abonner', + 'lock' => 'Verrouiller', + 'unlock' => 'Déverrouiller', + 'unlock_form' => [ + 'title' => 'Contenu Premium', + 'subtitle' => 'Ce podcast contient des épisodes premium verrouillés ! Avez-vous la clé pour les déverrouiller ?', + 'token' => 'Entrez votre clé', + 'token_hint' => 'Si vous êtes abonné à {podcastTitle}, vous pouvez copier la clé qui vous a été envoyée par e-mail et la coller ici.', + 'submit' => 'Débloquer tous les épisodes!', + 'call_to_action' => 'Débloquer tous les épisodes de {podcastTitle}:', + 'subscribe_cta' => 'Je m’inscris maintenant !', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast débloqué avec succès ! Profitez des épisodes premium !', + 'unlockBadAttempt' => 'Votre clé ne semble pas fonctionner…', + 'lockSuccess' => 'Le podcast a été verouillé avec succès !', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr/Subscription.php b/modules/PremiumPodcasts/Language/fr/Subscription.php new file mode 100644 index 00000000..f760c1ae --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr/Subscription.php @@ -0,0 +1,100 @@ + 'Abonnements au podcast', + 'add' => 'Nouvel abonnement', + 'view' => 'Afficher l\'abonnement', + 'edit' => 'Modifier l\'inscription', + 'regenerate_token' => 'Regenerer le token', + 'suspend' => 'Suspendre l\'abonnement', + 'resume' => 'Reprendre l\'abonnement', + 'delete' => 'Supprimer l\'abonnement', + 'status' => [ + 'active' => 'Actif', + 'suspended' => 'Suspendu', + 'expired' => 'Expiré', + ], + 'list' => [ + 'number' => 'Numéro', + 'email' => 'Adresse e-mail', + 'expiration_date' => 'Date d\'expiration', + 'unlimited' => 'Illimité', + 'downloads' => 'Téléchargements', + 'status' => 'Statut', + ], + 'form' => [ + 'email' => 'Adresse e-mail', + 'expiration_date' => 'Date d\'expiration', + 'expiration_date_hint' => 'La date et l\'heure à laquelle l\'abonnement expire. Laissez vide pour un abonnement illimité.', + 'submit_create' => 'Créer un abonnement', + 'submit_edit' => 'Modifier l\'inscription', + ], + 'form_link_add' => [ + 'link' => 'Lien vers la page d\'abonnement', + 'link_hint' => 'Cela va ajouter un appel à l\'action dans le site Web invitant les auditeurs à s\'abonner au podcast.', + 'submit' => 'Enregistrer le lien', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspendre l\'abonnement empêchera l\'abonné d\'avoir accès au contenu premium. Vous pourrez toujours lever la suspension par la suite.', + 'reason' => 'Raison', + 'reason_placeholder' => 'Pour quelle raison arrêtez vous votre abonnement ?', + "submit" => 'Suspendre l\'abonnement', + ], + 'delete_form' => [ + 'disclaimer' => 'La suppression de l\'abonnement de {subscriber} supprimera toutes les données d\'analyse qui lui sont associées.', + 'understand' => 'Je comprends, supprimez l\'abonnement définitivement', + 'submit' => 'Supprimer l\'abonnement', + ], + 'messages' => [ + 'addSuccess' => 'Un nouvel abonnement a été ajouté ! Un e-mail de bienvenue a été envoyé à {subscriber}.', + 'addError' => 'L\'abonnement n\'a pu être ajouté.', + 'editSuccess' => 'La date d\'expiration de l\'abonnement a été mise à jour ! Un e-mail a été envoyé à {subscriber}.', + 'editError' => 'L\'abonnement n\'a pas pu être modifié.', + 'regenerateTokenSuccess' => 'Jeton régénéré ! Un email a été envoyé à {subscriber} avec le nouveau jeton.', + 'regenerateTokenError' => 'Le jeton n\'a pas pu être régénéré.', + 'deleteSuccess' => 'L\'abonnement a été suspendu! Un e-mail a été envoyé à {subscriber}.', + 'deleteError' => 'L\'abonnement n\'a pas pu être supprimé.', + 'suspendSuccess' => 'L\'abonnement a été suspendu! Un e-mail a été envoyé à {subscriber}.', + 'suspendError' => 'L\'abonnement ne peut pas être suspendu.', + 'resumeSuccess' => 'L\'abonnement a été suspendu! Un e-mail a été envoyé à {subscriber}.', + 'resumeError' => 'L\'abonnement n\'a pas pu être repris.', + 'linkSaveSuccess' => 'Le lien de l\'abonnement a été enregistré avec succès ! Il apparaîtra sur le site comme un Appel à l\'action !', + 'linkRemoveSuccess' => 'Le lien de l\'abonnement a été supprimé avec succès !', + ], + 'emails' => [ + 'greeting' => 'Hé,', + 'token' => 'Votre jeton : {0}', + 'unique_feed_link' => 'Votre lien de flux unique : {0}', + 'how_to_use' => 'Comment l\'utiliser ?', + 'two_ways' => 'Vous avez deux façons de débloquer les épisodes premium :', + 'import_into_app' => 'Copiez votre URL de flux unique dans votre application de baladodiffusion préférée (importez-la en tant que flux privé pour éviter de dévoiler vos identifiants).', + 'go_to_website' => 'Rendez-vous sur le site web de {podcastWebsite} et débloquez le podcast avec votre jeton.', + 'welcome_subject' => 'Bienvenue sur {podcastTitle}', + 'welcome' => 'Vous vous êtes abonné à {podcastTitle}, merci et bienvenue à bord !', + 'welcome_token_title' => 'Voici vos identifiants pour débloquer les épisodes premium du podcast:', + 'welcome_expires' => 'Votre abonnement a été configuré pour expirer le {0}.', + 'welcome_never_expires' => 'Votre abonnement a été configuré pour ne jamais expirer.', + 'reset_subject' => 'Votre jeton a été réinitialisé !', + 'reset_token' => 'Votre accès à {podcastTitle} a été réinitialisé !', + 'reset_token_title' => 'De nouveaux identifiants ont été générés pour vous permettre de déverrouiller les épisodes premium du podcast:', + 'edited_subject' => 'Votre abonnement a été mis à jour !', + 'edited_expires' => 'Votre abonnement pour {podcastTitle} a été configuré pour expirer le {expiresAt}.', + 'edited_never_expires' => 'Votre abonnement pour {podcastTitle} a été configuré pour ne jamais expirer !', + 'suspended_subject' => 'Votre abonnement a été suspendu !', + 'suspended' => 'Votre abonnement à {podcastTitle} a été suspendu ! Vous ne pouvez plus accéder aux épisodes premium du podcast.', + 'suspended_reason' => 'Pour la raison suivante : {0}', + 'resumed_subject' => 'Votre abonnement a été réactivé !', + 'resumed' => 'Votre abonnement à {podcastTitle} a été réactivé ! Vous pouvez à nouveau accéder aux épisodes premium du podcast.', + 'deleted_subject' => 'Votre abonnement a été supprimé !', + 'deleted' => 'Votre abonnement pour {podcastTitle} a été supprimé ! Vous n\'avez plus accès aux épisodes premium du podcast.', + 'footer' => '{castopod} hébergé sur {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr2/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/fr2/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr2/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/fr2/Subscription.php b/modules/PremiumPodcasts/Language/fr2/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/fr2/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/gd/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/gd/PremiumPodcasts.php new file mode 100644 index 00000000..ac6d33e4 --- /dev/null +++ b/modules/PremiumPodcasts/Language/gd/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Tha eapasodan premium aig a’ phod-chraoladh seo', + 'episode_is_premium' => 'Seo eapasod premium, chan eil e ri fhaighinn ach do dh’fho-sgrìobhaichean premium', + 'unlock_episode' => 'Tha an t-eapasod seo do dh’fho-sgrìobhaichean premium a-mhàin. Briog air gus a’ ghlas a thoirt fo bhàrr!', + 'banner_unlock' => 'Tha eapasodan premium sa phod-chraoladh seo nach eil ri fhaighinn ach do dh’fho-sgrìobhaichean premium.', + 'banner_lock' => 'Thug thu a’ ghlas far a’ phod-chraolaidh, gabh tlachd às na h-eapasodan premium!', + 'subscribe' => 'Fo-sgrìobh', + 'lock' => 'Glais', + 'unlock' => 'Thoir a’ ghlas dheth', + 'unlock_form' => [ + 'title' => 'Susbaint premium', + 'subtitle' => 'Tha eapasodan premium glaiste aig a’ phod-chraoladh seo! A bheil iuchair agad gus a’ ghlas a thoirt fo am bàrr?', + 'token' => 'Cuir a-steach an iuchair agad', + 'token_hint' => 'Ma fhuair thu fo-sgrìobhadh air {podcastTitle}, ’s urrainn dhut lethbhreac a dhèanamh dhen iuchair a chaidh a chur thugad air a’ phost-d ’s a cur ann an-seo.', + 'submit' => 'Thoir a’ ghlas far a h-uile eapasod!', + 'call_to_action' => 'Thoir a’ ghlas far a h-uile eapasod aig {podcastTitle}:', + 'subscribe_cta' => 'Fo-sgrìobh an-dràsta!', + ], + 'messages' => [ + 'unlockSuccess' => 'Thug thu a’ ghlas far a’ phod-chraolaidh! Gabh tlachd às na h-eapasodan premium!', + 'unlockBadAttempt' => 'Tha coltas nach eil an iuchair agad ag obair…', + 'lockSuccess' => 'Chaidh am pod-chraoladh a ghlasadh!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/gd/Subscription.php b/modules/PremiumPodcasts/Language/gd/Subscription.php new file mode 100644 index 00000000..2dbfdeb6 --- /dev/null +++ b/modules/PremiumPodcasts/Language/gd/Subscription.php @@ -0,0 +1,100 @@ + 'Fo-sgrìobhaidhean air pod-chraolaidhean', + 'add' => 'Fo-sgrìobhadh ùr', + 'view' => 'Seall am fo-sgrìobhadh', + 'edit' => 'Deasaich am fo-sgrìobhadh', + 'regenerate_token' => 'Ath-ghin an tòcan', + 'suspend' => 'Cuir am fo-sgrìobhadh à rèim', + 'resume' => 'Lean air an fho-sgrìobhadh', + 'delete' => 'Sguab às am fo-sgrìobhadh', + 'status' => [ + 'active' => 'Gnìomhach', + 'suspended' => 'À rèim', + 'expired' => 'Dh’fhalbh an ùine air', + ], + 'list' => [ + 'number' => 'Àireamh', + 'email' => 'Post-d', + 'expiration_date' => 'Ceann-là crìochnachaidh', + 'unlimited' => 'Gun chrìoch', + 'downloads' => 'Luchdaidhean a-nuas', + 'status' => 'Staid', + ], + 'form' => [ + 'email' => 'Post-d', + 'expiration_date' => 'Ceann-là crìochnachaidh', + 'expiration_date_hint' => 'An ceann-là ’s àm a dh’fhalbhas an ùine air an fho-sgrìobhadh. Fàg bàn e airson fo-sgrìobhadh gun chrìoch.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Deasaich am fo-sgrìobhadh', + ], + 'form_link_add' => [ + 'link' => 'Ceangal gu duilleag an fho-sgrìobhaidh', + 'link_hint' => 'Cuiridh seo tàladh ris an làrach-lìn a bheir cuireadh dhan luchd-èisteachd ach am faigh iad fo-sgrìobhadh air a’ phod-chraoladh.', + 'submit' => 'Sàbhail an ceangal', + ], + 'suspend_form' => [ + 'disclaimer' => 'Ma chuireas tu am fo-sgrìobhadh à rèim, cuingichidh seo an neach fo-sgrìobhaidh gus nach fhaigh iad cothrom air susbaint premium. ’S urrainn dhut a chur ann an rèim a-rithist uair sam bith an uairsin.', + 'reason' => 'Adhbhar', + 'reason_placeholder' => 'Carson a tha thu a’ cur am fo-sgrìobhadh à rèim?', + "submit" => 'Cuir am fo-sgrìobhadh à rèim', + ], + 'delete_form' => [ + 'disclaimer' => 'Ma sguabas tu às am fo-sgrìobhadh aig {subscriber}, bheir seo air falbh dàta sam bith na h-anailiseachd a tha co-cheangailte ris.', + 'understand' => 'Tha mi agaibh, thoir air falbh am fo-sgrìobhadh gu buan', + 'submit' => 'Thoir am fo-sgrìobhadh air falbh', + ], + 'messages' => [ + 'addSuccess' => 'Chaidh fo-sgrìobhadh ùr a chur ris! Chaidh post-d fàilteachaidh a chur gu {subscriber}.', + 'addError' => 'Cha b’ urrainn dhuinn am fo-sgrìobhadh a chur ris.', + 'editSuccess' => 'Chaidh an ceann-là a dh’fhalbhas an ùine air an fho-sgrìobhadh ùrachadh! Chaidh post-d a chur gu {subscriber}.', + 'editError' => 'Cha b’ urrainn dhuinn am fo-sgrìobhadh a dheasachadh.', + 'regenerateTokenSuccess' => 'Chaidh an tòcan ath-ghintinn! Chaidh post-d a chur gu {subscriber} leis an tòcan ùr.', + 'regenerateTokenError' => 'Cha b’ urrainn dhuinn an tòcan ath-ghintinn.', + 'deleteSuccess' => 'Chaidh am fo-sgrìobhadh a thoirt air falbh! Chaidh post-d a chur gu {subscriber}.', + 'deleteError' => 'Cha b’ urrainn dhuinn am fo-sgrìobhadh a thoirt air falbh.', + 'suspendSuccess' => 'Chaidh am fo-sgrìobhadh a chur à rèim! Chaidh post-d a chur gu {subscriber}.', + 'suspendError' => 'Cha b’ urrainn dhuinn am fo-sgrìobhadh a cur à rèim.', + 'resumeSuccess' => 'Chaidh leantainn air an fho-sgrìobhadh! Chaidh post-d a chur gu {subscriber}.', + 'resumeError' => 'Cha b’ urrainn dhuinn leantainn air an fho-sgrìobhadh.', + 'linkSaveSuccess' => 'Chaidh an ceangal dhan fho-sgrìobhadh a shàbhaladh! Nochdaidh e air an làrach-lìn na thadhladh!', + 'linkRemoveSuccess' => 'Chaidh an ceangal dhan fho-sgrìobhadh a thoirt air falbh!', + ], + 'emails' => [ + 'greeting' => 'Shin thu,', + 'token' => 'Seo an tòcan agad: {0}', + 'unique_feed_link' => 'Seo ceangal àraidh an inbhir agad: {0}', + 'how_to_use' => 'Mar a chleachdas tu e', + 'two_ways' => 'Tha dà dhòigh ann air an doir thu a’ ghlas far eapasodan premium:', + 'import_into_app' => 'Cuir lethbhreac de dh’URL àraidh an inbhir agad san aplacaid pod-chraolaidh as fheàrr leat (ion-phortaich e ’na inbhir prìobhaideach ach nach foillsich thu an teisteanas agad).', + 'go_to_website' => 'Tadhail air an làrach-lìn aig {podcastWebsite} agus thoir a’ ghlas far a’ phod-chraolaidh leis an tòcan agad.', + 'welcome_subject' => 'Fàilte gu {podcastTitle}', + 'welcome' => 'Fhuair thu fo-sgrìobhadh air {podcastTitle}, mòran taing is fàilte air bhòrd!', + 'welcome_token_title' => 'Seo an teisteanas agad airson a’ ghlas a thoirt far eapasodan premium a’ phod-chraolaidh:', + 'welcome_expires' => 'Chaidh crìoch an fho-sgrìobhaidh agad a shuidheachadh air {0}.', + 'welcome_never_expires' => 'Chaidh am fo-sgrìobhaidh agad a shuidheachadh ach nach fhalbh an ùine air.', + 'reset_subject' => 'Chaidh an tòcan agad ath-shuidheachadh!', + 'reset_token' => 'Chaidh an t-inntrigeadh agad air {podcastTitle} ath-shuidheachadh!', + 'reset_token_title' => 'Chaidh teisteanas ùr a ghintinn dhut airson a’ ghlas a thoirt far eapasodan premium a’ phod-chraolaidh:', + 'edited_subject' => 'Chaidh am fo-sgrìobhadh agad ùrachadh!', + 'edited_expires' => 'Chaidh crìoch an fho-sgrìobhaidh agad air {podcastTitle} a shuidheachadh air {expiresAt}.', + 'edited_never_expires' => 'Chaidh am fo-sgrìobhaidh agad air {podcastTitle} a shuidheachadh ach nach fhalbh an ùine air!', + 'suspended_subject' => 'Chaidh am fo-sgrìobhadh agad a chur à rèim!', + 'suspended' => 'Chaidh am fo-sgrìobhadh agad air {podcastTitle} a chur à rèim! Chan urrainn dhut eapasodan premium a’ phod-chraolaidh inntrigeadh tuilleadh.', + 'suspended_reason' => 'Seo as adhbhar dha: {0}', + 'resumed_subject' => 'Chaidh leantainn air an fho-sgrìobhadh agad!', + 'resumed' => 'Chaidh leantainn air an fho-sgrìobhadh air {podcastTitle} agad! ’S urrainn dhut eapasodan premium a’ phod-chraolaidh inntrigeadh a-rithist.', + 'deleted_subject' => 'Chaidh am fo-sgrìobhadh agad a thoirt air falbh!', + 'deleted' => 'Chaidh am fo-sgrìobhadh agad air {podcastTitle} a thoirt air falbh! Chan urrainn dhut eapasodan premium a’ phod-chraolaidh inntrigeadh tuilleadh.', + 'footer' => 'Seo {castopod} ’ga òstadh air {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/gl/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/gl/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/gl/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/gl/Subscription.php b/modules/PremiumPodcasts/Language/gl/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/gl/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/id/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/id/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/id/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/id/Subscription.php b/modules/PremiumPodcasts/Language/id/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/id/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/it/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/it/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/it/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/it/Subscription.php b/modules/PremiumPodcasts/Language/it/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/it/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ja/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ja/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ja/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ja/Subscription.php b/modules/PremiumPodcasts/Language/ja/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ja/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/kk/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/kk/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/kk/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/kk/Subscription.php b/modules/PremiumPodcasts/Language/kk/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/kk/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ko/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ko/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ko/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ko/Subscription.php b/modules/PremiumPodcasts/Language/ko/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ko/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/nl/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/nl/PremiumPodcasts.php new file mode 100644 index 00000000..8c05e623 --- /dev/null +++ b/modules/PremiumPodcasts/Language/nl/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast bevat premium afleveringen', + 'episode_is_premium' => 'Aflevering is premium, alleen beschikbaar voor premium abonnees', + 'unlock_episode' => 'Deze aflevering is alleen voor premium abonnees. Klik om te ontgrendelen!', + 'banner_unlock' => 'Deze podcast bevat premium afleveringen, alleen beschikbaar voor premium abonnees.', + 'banner_lock' => 'Podcast is ontgrendeld, geniet van de premium afleveringen!', + 'subscribe' => 'Abonneren', + 'lock' => 'Vergrendel', + 'unlock' => 'Ontgrendel', + 'unlock_form' => [ + 'title' => 'Premium inhoud', + 'subtitle' => 'Deze podcast bevat vergrendelde premium afleveringen! Heb je de sleutel om ze te ontgrendelen?', + 'token' => 'Voer jouw sleutel in', + 'token_hint' => 'Als je geabonneerd bent op {podcastTitle}, kun je de sleutel die naar je verzonden is via e-mail kopiëren en deze hier plakken.', + 'submit' => 'Ontgrendel alle afleveringen!', + 'call_to_action' => 'Ontgrendel alle afleveringen van {podcastTitle}:', + 'subscribe_cta' => 'Nu abonneren!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast is succesvol ontgrendeld! Geniet van de premium afleveringen!', + 'unlockBadAttempt' => 'Jouw sleutel lijkt niet te werken…', + 'lockSuccess' => 'Podcast is succesvol vergrendeld!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/nl/Subscription.php b/modules/PremiumPodcasts/Language/nl/Subscription.php new file mode 100644 index 00000000..36bc8976 --- /dev/null +++ b/modules/PremiumPodcasts/Language/nl/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast abonnementen', + 'add' => 'Nieuw abonnement', + 'view' => 'Bekijk abonnement', + 'edit' => 'Bewerk abonnement', + 'regenerate_token' => 'Sleutel opnieuw genereren', + 'suspend' => 'Abonnement opschorten', + 'resume' => 'Abonnement hervatten', + 'delete' => 'Abonnement verwijderen', + 'status' => [ + 'active' => 'Actief', + 'suspended' => 'Opgeschort', + 'expired' => 'Verlopen', + ], + 'list' => [ + 'number' => 'Nummer', + 'email' => 'E-mail', + 'expiration_date' => 'Vervaldatum', + 'unlimited' => 'Onbeperkt', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'E-mail', + 'expiration_date' => 'Vervaldatum', + 'expiration_date_hint' => 'De datum en tijd waarop het abonnement verloopt. Laat leeg voor een onbeperkt abonnement.', + 'submit_create' => 'Abonnement aanmaken', + 'submit_edit' => 'Bewerk abonnement', + ], + 'form_link_add' => [ + 'link' => 'Abonnementspagina link', + 'link_hint' => 'Dit zal een call-to-action toevoegen op de website die luisteraars uitnodigt om zich te abonneren op de podcast.', + 'submit' => 'Link opslaan', + ], + 'suspend_form' => [ + 'disclaimer' => 'Opschorting van het abonnement zorgt ervoor dat de abonnee geen toegang meer heeft tot premium inhoud. U kunt de opschorting op ieder moment opheffen.', + 'reason' => 'Reden', + 'reason_placeholder' => 'Waarom wilt u het abonnement onderbreken?', + "submit" => 'Abonnement opschorten', + ], + 'delete_form' => [ + 'disclaimer' => 'Het verwijderen van het abonnement van {subscriber} zal alle statistieken ervan verwijderen.', + 'understand' => 'Ik begrijp het, verwijder het abonnement permanent', + 'submit' => 'Abonnement verwijderen', + ], + 'messages' => [ + 'addSuccess' => 'Nieuw abonnement toegevoegd! Er is een welkomstmail is naar {subscriber} gestuurd.', + 'addError' => 'Abonnement kon niet worden toegevoegd.', + 'editSuccess' => 'Abonnement vervaldatum is bijgewerkt! Er is een e-mail verzonden naar {subscriber}.', + 'editError' => 'Abonnement kon niet worden bijgewerkt.', + 'regenerateTokenSuccess' => 'Token vernieuwd! Er is een e-mail verzonden naar {subscriber} met de nieuwe gegevens.', + 'regenerateTokenError' => 'Token kon niet worden vernieuwd.', + 'deleteSuccess' => 'Abonnement is verwijderd! Er is een e-mail verzonden naar {subscriber}.', + 'deleteError' => 'Abonnement kon niet worden verwijderd.', + 'suspendSuccess' => 'Abonnement is opgeschort! Er is een e-mail verzonden naar {subscriber}.', + 'suspendError' => 'Abonnement kon niet opgeschort worden.', + 'resumeSuccess' => 'Abonnement is hervat! Er is een e-mail verzonden naar {subscriber}.', + 'resumeError' => 'Abonnement kon niet worden hervat.', + 'linkSaveSuccess' => 'Abonnementlink is succesvol opgeslagen! Het zal verschijnen op de website als een call-to-action!', + 'linkRemoveSuccess' => 'Abonnementlink is succesvol verwijderd!', + ], + 'emails' => [ + 'greeting' => 'Hoi,', + 'token' => 'Uw token: {0}', + 'unique_feed_link' => 'Uw persoonlijke feed: {0}', + 'how_to_use' => 'Gebruiksaanwijzing', + 'two_ways' => 'Je hebt twee manieren om toegang te krijgen tot de premium afleveringen:', + 'import_into_app' => 'Kopieer uw persoonlijke feed in je favoriete podcast app (importeer deze als een privé feed om te voorkomen dat je inloggegevens worden gedeeld).', + 'go_to_website' => 'Ga naar de website van {podcastWebsite} en krijgt toegang tot de podcast met uw persoonlijke token.', + 'welcome_subject' => 'Welkom bij {podcastTitle}', + 'welcome' => 'Je bent geabonneerd op {podcastTitle}, bedankt en welkom bij de club!', + 'welcome_token_title' => 'Hier zijn uw inloggegevens om toegang te krijgen tot de premium afleveringen van de podcast:', + 'welcome_expires' => 'Uw abonnement verloopt op {0}.', + 'welcome_never_expires' => 'Uw abonnement stopt niet automatisch.', + 'reset_subject' => 'Je token is vernieuwd!', + 'reset_token' => 'Uw toegang tot {podcastTitle} is gereset!', + 'reset_token_title' => 'Nieuwe inloggegevens zijn gegenereerd om toegang tot de premium afleveringen van de podcast te krijgen:', + 'edited_subject' => 'Uw abonnement is bijgewerkt!', + 'edited_expires' => 'Je abonnement voor {podcastTitle} vervalt op {expiresAt}.', + 'edited_never_expires' => 'Je abonnement voor {podcastTitle} is ingesteld om niet automatisch te verlopen!', + 'suspended_subject' => 'Uw abonnement is opgeschort!', + 'suspended' => 'Uw abonnement voor {podcastTitle} is opgeschort! U heeft niet langer toegang tot de premium afleveringen van de podcast.', + 'suspended_reason' => 'Dat is gebeurd om de volgende reden: {0}', + 'resumed_subject' => 'Uw abonnement is hervat!', + 'resumed' => 'Uw abonnement op {podcastTitle} is hervat! U heeft weer toegang tot de premium afleveringen van de podcast.', + 'deleted_subject' => 'Uw abonnement is beëindigd!', + 'deleted' => 'Uw abonnement op {podcastTitle} is verwijderd! U heeft niet langer toegang tot de premium afleveringen van de podcast.', + 'footer' => '{castopod} gehost op {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/nn-no/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/nn-no/PremiumPodcasts.php new file mode 100644 index 00000000..4decf740 --- /dev/null +++ b/modules/PremiumPodcasts/Language/nn-no/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podkasten inneheld betalte episodar', + 'episode_is_premium' => 'Episoden er bak betalingsmur. Berre betalande abonnentar har tilgang', + 'unlock_episode' => 'Denne episoden er berre for betalande abonnentar. Klikk for å få tilgang!', + 'banner_unlock' => 'Denne podkasten inneheld episodar som berre er tilgjengelege for betalande abonnentar.', + 'banner_lock' => 'Podkasten er låst opp, så no kan du høyra på dei betalte episodane!', + 'subscribe' => 'Abonner', + 'lock' => 'Lås', + 'unlock' => 'Lås opp', + 'unlock_form' => [ + 'title' => 'Betalt innhald', + 'subtitle' => 'Denne podkasten inneheld episodar bak betalingsmur. Har du nykelen for å få tilgang til dei?', + 'token' => 'Skriv inn nykelen', + 'token_hint' => 'Viss du abonnerer på {podcastTitle}, kan du kopiera nykelen du fekk på epost og lima han inn her.', + 'submit' => 'Få tilgang til alle episodane!', + 'call_to_action' => 'Få tilgang til alle episodane av {podcastTitle}:', + 'subscribe_cta' => 'Abonner no!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podkasten er låst opp. No kan du høyra på dei betalte episodane!', + 'unlockBadAttempt' => 'Nykelen din fungerer ikkje…', + 'lockSuccess' => 'Podkasten er låst.', + ], +]; diff --git a/modules/PremiumPodcasts/Language/nn-no/Subscription.php b/modules/PremiumPodcasts/Language/nn-no/Subscription.php new file mode 100644 index 00000000..d32055c8 --- /dev/null +++ b/modules/PremiumPodcasts/Language/nn-no/Subscription.php @@ -0,0 +1,100 @@ + 'Abonnement til podkasten', + 'add' => 'Nytt abonnement', + 'view' => 'Vis abonnementet', + 'edit' => 'Rediger abonnementet', + 'regenerate_token' => 'Regenerer nykel', + 'suspend' => 'Stopp abonnementet', + 'resume' => 'Start oppatt abonnementet', + 'delete' => 'Slett abonnementet', + 'status' => [ + 'active' => 'Aktiv', + 'suspended' => 'Stoppa', + 'expired' => 'Utgått', + ], + 'list' => [ + 'number' => 'Nummer', + 'email' => 'Epost', + 'expiration_date' => 'Gyldig til', + 'unlimited' => 'Uavgrensa', + 'downloads' => 'Nedlastingar', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Epost', + 'expiration_date' => 'Gyldig til', + 'expiration_date_hint' => 'Datoen og tidspunket abonnementet stoppar. La det stå tomt viss abonnementet skal gå utan sluttdato.', + 'submit_create' => 'Opprett abonnement', + 'submit_edit' => 'Rediger abonnementet', + ], + 'form_link_add' => [ + 'link' => 'Lenke til abonnementssida', + 'link_hint' => 'Her legg du til ei oppmoding på nettsida di, der du inviterer lyttarane til å abonnera på podkasten din.', + 'submit' => 'Lagre lenka', + ], + 'suspend_form' => [ + 'disclaimer' => 'Viss du stoppar abonnementet, vil ikkje abonnenten lenger få tilgang til betalt innhald. Du kan starta abonnementet att seinare.', + 'reason' => 'Grunngjeving', + 'reason_placeholder' => 'Kvifor stoppar du abonnementet?', + "submit" => 'Stopp abonnementet', + ], + 'delete_form' => [ + 'disclaimer' => 'Viss du slettar abonnementet til {subscriber}, slettar du òg alle analysedata knytt til abonnementet.', + 'understand' => 'Eg forstår, slett abonnementet', + 'submit' => 'Slett abonnementet', + ], + 'messages' => [ + 'addSuccess' => 'Du har fått ein ny abonnent! Me har sendt ein velkomstepost til {subscriber}.', + 'addError' => 'Greidde ikkje leggja til abonnementet.', + 'editSuccess' => 'Stoppdatoen for abonnementet er oppdatert! Me har sendt ein epost til {subscriber}.', + 'editError' => 'Greidde ikkje redigera abonnementet.', + 'regenerateTokenSuccess' => 'Nykelen er regenerert! Me sende ein epost til {subscriber} med den nye nykelen.', + 'regenerateTokenError' => 'Greidde ikkje regenerera nykelen.', + 'deleteSuccess' => 'Abonnementet er sletta! Me sende ein epost til {subscriber}.', + 'deleteError' => 'Greidde ikkje sletta abonnementet.', + 'suspendSuccess' => 'Abonnementet vart stoppa! Me sende ein epost til {subscriber}.', + 'suspendError' => 'Greidde ikkje stoppa abonnementet.', + 'resumeSuccess' => 'Abonnementet er starta att! Me sende ein epost til {subscriber}.', + 'resumeError' => 'Greidde ikkje starta abonnementet att.', + 'linkSaveSuccess' => 'Abonnementslenka er lagra. Ho vil visa på nettstaden som ei handlingsvarsling.', + 'linkRemoveSuccess' => 'Abonnementslenka vart fjerna.', + ], + 'emails' => [ + 'greeting' => 'Hei', + 'token' => 'Nykelen din: {0}', + 'unique_feed_link' => 'Den unike lenka til straumen: {0}', + 'how_to_use' => 'Korleis skal eg bruka dette?', + 'two_ways' => 'Du kan låsa opp betalte episodar på to måtar:', + 'import_into_app' => 'Kopier den unike adressa til podkaststraumen til favoritt-podkastappen din (importer adressa som ein privat straum slik at du ikkje avslører innloggingsopplysingane dine).', + 'go_to_website' => 'Gå til heimesida til {podcastWebsite} og lås opp podkasten med nykelen.', + 'welcome_subject' => 'Velkomen til {podcastTitle}', + 'welcome' => 'Du abonnerer på {podcastTitle}. Takk, og velkomen ombord!', + 'welcome_token_title' => 'Her er nykelen for å få tilgang til dei betalte episodane til podkasten:', + 'welcome_expires' => 'Abonnementet ditt hadde stoppdato {0}.', + 'welcome_never_expires' => 'Abonnementet ditt hadde ingen stoppdato.', + 'reset_subject' => 'Nykelen din er nullstilt!', + 'reset_token' => 'Tilgangen din til {podcastTitle} er nullstilt!', + 'reset_token_title' => 'Me har laga nye tilgangsopplysingar for deg for å få tilgang til dei betalte episodane til podkasten:', + 'edited_subject' => 'Abonnementet ditt er oppdatert!', + 'edited_expires' => 'Abonnementet ditt på {podcastTitle} hadde stoppdato {expiresAt}.', + 'edited_never_expires' => 'Abonnementet ditt på {podcastTitle} hadde ingen stoppdato!', + 'suspended_subject' => 'Abonnementet ditt er stoppa!', + 'suspended' => 'Abonnementet ditt på {podcastTitle} er stoppa! Du har ikkje lenger tilgang til dei betalte episodane til denne podkasten.', + 'suspended_reason' => 'Det er av desse grunnane: {0}', + 'resumed_subject' => 'Abonnementet ditt har starta att!', + 'resumed' => 'Abonnementet ditt på {podcastTitle} har starta att! Du har tilgang til dei betalte episodane til denne podkasten.', + 'deleted_subject' => 'Abonnementet ditt er sletta!', + 'deleted' => 'Abonnementet ditt på {podcastTitle} er sletta! Du har ikkje lenger tilgang til dei betalte episodane til podkasten.', + 'footer' => '{castopod} køyrer på {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/oc/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/oc/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/oc/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/oc/Subscription.php b/modules/PremiumPodcasts/Language/oc/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/oc/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pl/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/pl/PremiumPodcasts.php new file mode 100644 index 00000000..d9a3d493 --- /dev/null +++ b/modules/PremiumPodcasts/Language/pl/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast zawiera odcinki premium', + 'episode_is_premium' => 'Ten odcinek premium jest dostępny tylko dla subskrybentów', + 'unlock_episode' => 'Ten odcinek jest tylko dla subskrybentów premium. Kliknij, aby go odblokować!', + 'banner_unlock' => 'Ten podcast zawiera odcinki premium, dostępne tylko dla subskrybentów premium.', + 'banner_lock' => 'Podcast został odblokowany, ciesz się odcinkami premium!', + 'subscribe' => 'Subskrybuj', + 'lock' => 'Zablokuj', + 'unlock' => 'Odblokuj', + 'unlock_form' => [ + 'title' => 'Zawartość premium', + 'subtitle' => 'Ten podcast zawiera zablokowane odcinki premium! Czy masz klucz do ich odblokowania?', + 'token' => 'Wprowadź swój klucz', + 'token_hint' => 'Jeśli subskrybujesz {podcastTitle}, możesz skopiować klucz wysłany do Ciebie mailem i wkleić go tutaj.', + 'submit' => 'Odblokuj wszystkie odcinki!', + 'call_to_action' => 'Odblokuj wszystkie odcinki {podcastTitle}:', + 'subscribe_cta' => 'Subskrybuj teraz!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast został pomyślnie odblokowany! Ciesz się odcinkami premium!', + 'unlockBadAttempt' => 'Twój klucz nie działa…', + 'lockSuccess' => 'Podcast został pomyślnie zablokowany!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pl/Subscription.php b/modules/PremiumPodcasts/Language/pl/Subscription.php new file mode 100644 index 00000000..8a81eca8 --- /dev/null +++ b/modules/PremiumPodcasts/Language/pl/Subscription.php @@ -0,0 +1,100 @@ + 'Subskrypcje podcastu', + 'add' => 'Nowa subskrypcja', + 'view' => 'Wyświetl subskrypcję', + 'edit' => 'Edytuj subskrypcję', + 'regenerate_token' => 'Wygeneruj nowy token', + 'suspend' => 'Wstrzymaj subskrypcję', + 'resume' => 'Wznów subskrypcję', + 'delete' => 'Usuń subskrypcję', + 'status' => [ + 'active' => 'Aktywne', + 'suspended' => 'Zawieszony', + 'expired' => 'Wygasły', + ], + 'list' => [ + 'number' => 'Numer', + 'email' => 'Email', + 'expiration_date' => 'Data ważności', + 'unlimited' => 'Nielimitowany', + 'downloads' => 'Pobrane', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Data ważności', + 'expiration_date_hint' => 'Data i godzina wygaśnięcia subskrypcji. Pozostaw puste dla nieograniczonej subskrypcji.', + 'submit_create' => 'Utwórz subskrypcję', + 'submit_edit' => 'Edytuj subskrypcję', + ], + 'form_link_add' => [ + 'link' => 'Link do strony subskrypcji', + 'link_hint' => 'Spowoduje to dodanie przycisku zapraszającego słuchaczy do subskrypcji podcastu.', + 'submit' => 'Zapisz link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Zawieszenie subskrypcji ograniczy subskrybentowi dostęp do treści premium. Wciąż będziesz mógł później cofnąć zawieszenie.', + 'reason' => 'Powód', + 'reason_placeholder' => 'Dlaczego zawieszasz subskrypcję?', + "submit" => 'Wstrzymaj subskrypcję', + ], + 'delete_form' => [ + 'disclaimer' => 'Usunięcie subskrypcji {subscriber} spowoduje usunięcie wszystkich danych analitycznych z nią związanych.', + 'understand' => 'Rozumiem, usuń subskrypcję na stałe', + 'submit' => 'Usuń subskrypcję', + ], + 'messages' => [ + 'addSuccess' => 'Dodano nową subskrypcję! Wiadomość powitalna została wysłana na adres {subscriber}.', + 'addError' => 'Subskrypcja nie mogła zostać dodana.', + 'editSuccess' => 'Data wygaśnięcia subskrypcji została zaktualizowana! Wiadomość e-mail została wysłana do {subscriber}.', + 'editError' => 'Subskrypcja nie mogła być edytowana.', + 'regenerateTokenSuccess' => 'Token został zresetowany! Wiadomość e-mail została wysłana do {subscriber} z nowym tokenem.', + 'regenerateTokenError' => 'Token nie mógł zostać zresetowany.', + 'deleteSuccess' => 'Subskrypcja została usunięta! Wiadomość e-mail została wysłana do {subscriber}.', + 'deleteError' => 'Subskrypcja nie mogła zostać usunięta.', + 'suspendSuccess' => 'Subskrypcja została zawieszona! Wiadomość e-mail została wysłana do {subscriber}.', + 'suspendError' => 'Subskrypcja nie mogła zostać zawieszona.', + 'resumeSuccess' => 'Subskrypcja została wznowiona! Wiadomość e-mail została wysłana do {subscriber}.', + 'resumeError' => 'Subskrypcja nie mogła zostać wznowiona.', + 'linkSaveSuccess' => 'Link do subskrypcji został pomyślnie zapisany! Pojawi się na stronie internetowej jako Call To Action!', + 'linkRemoveSuccess' => 'Link do subskrypcji został pomyślnie usunięty!', + ], + 'emails' => [ + 'greeting' => 'Cześć,', + 'token' => 'Twój token: {0}', + 'unique_feed_link' => 'Twój unikalny link do kanału: {0}', + 'how_to_use' => 'Jak używać?', + 'two_ways' => 'Masz dwa sposoby odblokowania odcinków premium:', + 'import_into_app' => 'Wklej swój unikalny adres URL kanału do swojej ulubionej aplikacji podcastowej (zaimportuj go jako prywatny kanał, aby zapobiec ujawnianiu Twoich tokenów).', + 'go_to_website' => 'Przejdź do strony {podcastWebsite} i odblokuj podcast za pomocą swojego tokenu.', + 'welcome_subject' => 'Witaj w {podcastTitle}', + 'welcome' => 'Zasubskrybowano {podcastTitle}, dziękuję i witam na pokładzie!', + 'welcome_token_title' => 'Oto twoje dane, aby odblokować odcinki premium podcastu:', + 'welcome_expires' => 'Twoja subskrypcja wygaśnie w dniu {0}.', + 'welcome_never_expires' => 'Twoja subskrypcja nigdy nie wygasa.', + 'reset_subject' => 'Twój token został zresetowany!', + 'reset_token' => 'Twój dostęp do {podcastTitle} został zresetowany!', + 'reset_token_title' => 'Wygenerowano nowe dane dostępowe do odblokowania odcinków premium podcastu:', + 'edited_subject' => 'Subskrypcja została zaktualizowana!', + 'edited_expires' => 'Twoja subskrypcja dla {podcastTitle} wygaśnie w dniu {expiresAt}.', + 'edited_never_expires' => 'Twoja subskrypcja dla {podcastTitle} nigdy nie wygaśnie!', + 'suspended_subject' => 'Twoja subskrypcja została zawieszona!', + 'suspended' => 'Twoja subskrypcja dla {podcastTitle} została zawieszona! Nie masz już dostępu do odcinków premium podcastu.', + 'suspended_reason' => 'Z następującego powodu: {0}', + 'resumed_subject' => 'Twoja subskrypcja została wznowiona!', + 'resumed' => 'Twoja subskrypcja dla {podcastTitle} została wznowiona! Masz ponownie dostęp do odcinków premium podcastu.', + 'deleted_subject' => 'Twoja subskrypcja została usunięta!', + 'deleted' => 'Twoja subskrypcja dla {podcastTitle} została usunięta! Nie masz już dostępu do odcinków premium podcastu.', + 'footer' => '{castopod} hostowane na {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pt-br/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/pt-br/PremiumPodcasts.php new file mode 100644 index 00000000..b85012d9 --- /dev/null +++ b/modules/PremiumPodcasts/Language/pt-br/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'O Podcast contém episódios premium', + 'episode_is_premium' => 'Episódio é premium, somente disponível para assinantes premium', + 'unlock_episode' => 'Este episódio é apenas para assinantes premium. Clique para desbloqueá-lo!', + 'banner_unlock' => 'Este podcast contém episódios premium, somente disponível para assinantes premium.', + 'banner_lock' => 'O Podcast desbloqueado, aproveite os episódios premium!', + 'subscribe' => 'Inscrever-se', + 'lock' => 'Bloquear', + 'unlock' => 'Desbloquear', + 'unlock_form' => [ + 'title' => 'Conteúdo premium', + 'subtitle' => 'Este podcast contém episódios premium bloqueados! Você tem a chave para desbloqueá-los?', + 'token' => 'Digite sua chave', + 'token_hint' => 'Se você se inscreveu no {podcastTitle}, você pode copiar a chave que foi enviada por email e colá-la aqui.', + 'submit' => 'Desbloquear todos os episódios!', + 'call_to_action' => 'Desbloquear todos os episódios de {podcastTitle}:', + 'subscribe_cta' => 'Inscreva-se agora!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast foi desbloqueado com sucesso! Aproveite os episódios premium!', + 'unlockBadAttempt' => 'Sua chave parece não estar funcionando…', + 'lockSuccess' => 'Podcast foi trancado com sucesso!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pt-br/Subscription.php b/modules/PremiumPodcasts/Language/pt-br/Subscription.php new file mode 100644 index 00000000..5e125494 --- /dev/null +++ b/modules/PremiumPodcasts/Language/pt-br/Subscription.php @@ -0,0 +1,100 @@ + 'Assinaturas de Podcast', + 'add' => 'Nova assinatura', + 'view' => 'Visualizar assinatura', + 'edit' => 'Editar assinatura', + 'regenerate_token' => 'Regerar token', + 'suspend' => 'Suspender assinatura', + 'resume' => 'Retomar assinatura', + 'delete' => 'Excluir assinatura', + 'status' => [ + 'active' => 'Ativo', + 'suspended' => 'Suspenso', + 'expired' => 'Expirado', + ], + 'list' => [ + 'number' => 'Número', + 'email' => 'E-mail', + 'expiration_date' => 'Data da expiração', + 'unlimited' => 'Sem limite', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'E-mail', + 'expiration_date' => 'Data da expiração', + 'expiration_date_hint' => 'A data e hora em que a assinatura expirará. Deixe em branco para uma assinatura ilimitada.', + 'submit_create' => 'Criar assinatura', + 'submit_edit' => 'Editar assinatura', + ], + 'form_link_add' => [ + 'link' => 'Link da página de assinatura', + 'link_hint' => 'Isto irá adicionar uma chamada para a ação no site que convida ouvintes a se inscreverem no podcast.', + 'submit' => 'Salvar o link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pt/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/pt/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/pt/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/pt/Subscription.php b/modules/PremiumPodcasts/Language/pt/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/pt/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ro/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ro/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ro/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ro/Subscription.php b/modules/PremiumPodcasts/Language/ro/Subscription.php new file mode 100644 index 00000000..86a77ad8 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ro/Subscription.php @@ -0,0 +1,100 @@ + 'Abonamente Podcast', + 'add' => 'Abonament nou', + 'view' => 'Vizualizare abonament', + 'edit' => 'Editare abonament', + 'regenerate_token' => 'Regenerează token de autentificare', + 'suspend' => 'Suspendare abonament', + 'resume' => 'Reluare abonament', + 'delete' => 'Şterge abonamentul', + 'status' => [ + 'active' => 'Activ', + 'suspended' => 'Suspendat', + 'expired' => 'Expirat', + ], + 'list' => [ + 'number' => 'Număr', + 'email' => 'E-mail', + 'expiration_date' => 'Data expirării', + 'unlimited' => 'Nelimitat', + 'downloads' => 'Descărcări', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'E-mail', + 'expiration_date' => 'Data expirării', + 'expiration_date_hint' => 'Data și ora la care expiră abonamentul. Lăsați gol pentru un abonament nelimitat.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Editare abonament', + ], + 'form_link_add' => [ + 'link' => 'Link-ul paginii de abonare', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ru/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/ru/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/ru/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/ru/Subscription.php b/modules/PremiumPodcasts/Language/ru/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/ru/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sk/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/sk/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/sk/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sk/Subscription.php b/modules/PremiumPodcasts/Language/sk/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/sk/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sr-latn/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/sr-latn/PremiumPodcasts.php new file mode 100644 index 00000000..6da5e74e --- /dev/null +++ b/modules/PremiumPodcasts/Language/sr-latn/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast sadrži premijerne epizode', + 'episode_is_premium' => 'Epizoda je premijum, dostupna je samo premijum pretplatnicima', + 'unlock_episode' => 'Ova epizoda je samo za premijum pretplatnike. Klikni da je otključaš!', + 'banner_unlock' => 'Ovaj podkast sadrži premijum epizode, dostupne samo premijum pretplatnicima.', + 'banner_lock' => 'Podkast je otključan, uživajte u premijum epizodama!', + 'subscribe' => 'Pretplatite se', + 'lock' => 'Zaključaj', + 'unlock' => 'Otključaj', + 'unlock_form' => [ + 'title' => 'Premijum sadržaj', + 'subtitle' => 'Ovaj podkat sadrži zaključane premijum epizode! Da li imate ključ?', + 'token' => 'Unesite ključ', + 'token_hint' => 'Ako ste pretplaćeni na {podcastTitle}, možete kopirati ključ koji vam je poslat na E poštu i zalepiti ga ovde.', + 'submit' => 'Otključaj sve epizode!', + 'call_to_action' => 'Otključaj sve epizode {podcastTitle}:', + 'subscribe_cta' => 'Pretplati se sada!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podkast je uspešno otključan, uživajte u premijum epizodama!', + 'unlockBadAttempt' => 'Izgleda da vaš ključ ne radi…', + 'lockSuccess' => 'Podkast je uspešno zaključan!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sr-latn/Subscription.php b/modules/PremiumPodcasts/Language/sr-latn/Subscription.php new file mode 100644 index 00000000..0fbeb3aa --- /dev/null +++ b/modules/PremiumPodcasts/Language/sr-latn/Subscription.php @@ -0,0 +1,100 @@ + 'Podkast pretplate', + 'add' => 'Nova pretplata', + 'view' => 'Pogledaj pretplatu', + 'edit' => 'Uredi pretplatu', + 'regenerate_token' => 'Regeneriši token', + 'suspend' => 'Ukini pretplatu', + 'resume' => 'Nastavi pretplatu', + 'delete' => 'Obriši pretplatu', + 'status' => [ + 'active' => 'Aktivno', + 'suspended' => 'Ukinuto', + 'expired' => 'Isteklo', + ], + 'list' => [ + 'number' => 'Broj', + 'email' => 'E-pošta', + 'expiration_date' => 'Datum Isteka', + 'unlimited' => 'Neograničeno', + 'downloads' => 'Preuzimanja', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'E-pošta', + 'expiration_date' => 'Datum Isteka', + 'expiration_date_hint' => 'Datum i vreme kada pretplata ističe. Ostavite prazno za neograničenu pretplatu.', + 'submit_create' => 'Napravi pretplatu', + 'submit_edit' => 'Uredi pretplatu', + ], + 'form_link_add' => [ + 'link' => 'Veza strane za pretplate', + 'link_hint' => 'Ovo će dodati poziv na akciju na veb lokaciji koji poziva slušaoce da se pretplate na podkast.', + 'submit' => 'Sačuvaj vezu', + ], + 'suspend_form' => [ + 'disclaimer' => 'Obustavljanje pretplate će ograničiti pretplatniku pristup premijum sadržaju. I dalje ćete moći da uklonite obustavu nakon toga.', + 'reason' => 'Razlog', + 'reason_placeholder' => 'Zašto ukidate pretplatu?', + "submit" => 'Ukini pretplatu', + ], + 'delete_form' => [ + 'disclaimer' => 'Brisanje {subscriber} pretplate će ukloniti svu analitiku vezanu za tog pretplatnika.', + 'understand' => 'Razumem, želim da trajno ukinem pretplatu', + 'submit' => 'Ukloni pretplatu', + ], + 'messages' => [ + 'addSuccess' => 'Nova pretplata dodata! Poruka dobrodođlice je poslata {subscriber} putem E-pošte.', + 'addError' => 'Nije moguće dodati pretplatu.', + 'editSuccess' => 'Datum isteka pretplate je ažuriran! Poruka je poslata {subscriber} putem E-pošte.', + 'editError' => 'Nije moguće urediti pretplatu.', + 'regenerateTokenSuccess' => 'Token regenerisan! Novi token je poslat {subscriber} putem E-pošte.', + 'regenerateTokenError' => 'Token nije moguće regenerisati.', + 'deleteSuccess' => 'Pretplata je uklonjena! Poruka je poslata {subscriber} putem E-pošte.', + 'deleteError' => 'Nije moguće ukloniti pretplatu.', + 'suspendSuccess' => 'Pretplata je ukinuta! Poruka je poslata {subscriber} putem E-pošte.', + 'suspendError' => 'Nije moguće prekinuti pretplatu.', + 'resumeSuccess' => 'Pretplana je obnovljena! Poruka je poslata {subscriber} putem E-pošte.', + 'resumeError' => 'Nije moguće obnoviti pretplatu.', + 'linkSaveSuccess' => 'Veza za pretplatu je uspešno sačuvana! Pojaviće se na Veb strani kao poziv na akciju!', + 'linkRemoveSuccess' => 'Veza za pretplatu je uspešno uklonjena!', + ], + 'emails' => [ + 'greeting' => 'Hej,', + 'token' => 'Vaš token: {0}', + 'unique_feed_link' => 'Vaša jedinstvena veza sa fidom: {0}', + 'how_to_use' => 'Kako se koristi?', + 'two_ways' => 'Imate dva načina kako možete otključati premijum epizode:', + 'import_into_app' => 'Kopirajte svoj jedinstveni url fid u svoju omiljenu aplikaciju za podkaste (uvezite ga kao privatni fid da biste sprečili otkrivanje vaših akreditiva).', + 'go_to_website' => 'Idite na {podcastWebsite} veb stranicu i otključajte podkast koristeći vaš token.', + 'welcome_subject' => 'Dobrodošli na {podcastTitle}', + 'welcome' => 'Pretplatili ste se na {podcastTitle}, hvala vam i dobrodošli!', + 'welcome_token_title' => 'Evo vaših akreditiva kojima otključavate premijum epizode ovog podkasta:', + 'welcome_expires' => 'Vaša pretplata ističe {0}.', + 'welcome_never_expires' => 'Vaša pretplata je podešena tako da ne može da istekne.', + 'reset_subject' => 'Vaš token je resetovan!', + 'reset_token' => 'Vaš pristup {podcastTitle} je resetovan!', + 'reset_token_title' => 'Nove akreditive su kreirane kako bi ste pristupili premijum epizodama podkasta:', + 'edited_subject' => 'Vaša pretplata je ažurirana!', + 'edited_expires' => 'Vaša pretplata na {podcastTitle} ističe {expiresAt}.', + 'edited_never_expires' => 'Vaša pretplata na {podcastTitle} je podešena tako da nikad ne istekne!', + 'suspended_subject' => 'Vaša pretplata je ukinuta!', + 'suspended' => 'Vaša pretplata na {podcastTitle} je ukinuta! Više ne možete pristupiti premijum epizodama ovog podkasta.', + 'suspended_reason' => 'Razlog: {0}', + 'resumed_subject' => 'Vaša pretplata je ponovo pokrenuta!', + 'resumed' => 'Vaša pretplata na {podcastTitle} je ponovo pokrenuta! Sada ponovo možete pristupiti premijum epizodama ovog podkasta.', + 'deleted_subject' => 'Vaša pretplata je uklonjena!', + 'deleted' => 'Vaša pretplata na {podcastTitle} je uklonjena! Vipe ne možete pristupiti premijum epizodama ovog podkasta.', + 'footer' => '{castopod} hostovan na {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sv/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/sv/PremiumPodcasts.php new file mode 100644 index 00000000..21dcd34b --- /dev/null +++ b/modules/PremiumPodcasts/Language/sv/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast innehåller premium avsnitt', + 'episode_is_premium' => 'Avsnitt är premium, endast tillgängligt för premium-prenumeranter', + 'unlock_episode' => 'Denna episod är endast för premiumprenumeranter. Klicka för att låsa upp den!', + 'banner_unlock' => 'Denna podcast innehåller premiumavsnitt som endast är tillgängliga för premiumprenumeranter.', + 'banner_lock' => 'Podcast är olåst, njut av premiumavsnitt!', + 'subscribe' => 'Prenumerera', + 'lock' => 'Lås', + 'unlock' => 'Lås upp', + 'unlock_form' => [ + 'title' => 'Premium-innehåll', + 'subtitle' => 'Denna podcast innehåller låsta premium-avsnitt! Har du nyckeln för att låsa upp dem?', + 'token' => 'Ange din nyckel', + 'token_hint' => 'Om du prenumererar på {podcastTitle} kan du kopiera nyckeln som skickades till dig via e-post och klistra in den här.', + 'submit' => 'Lås upp alla avsnitt!', + 'call_to_action' => 'Lås upp alla avsnitt av {podcastTitle}:', + 'subscribe_cta' => 'Prenumerera nu!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast har låsts upp! Njut av premiumavsnitt!', + 'unlockBadAttempt' => 'Din nyckel verkar inte fungera…', + 'lockSuccess' => 'Podcast har låsts!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/sv/Subscription.php b/modules/PremiumPodcasts/Language/sv/Subscription.php new file mode 100644 index 00000000..06caf6cc --- /dev/null +++ b/modules/PremiumPodcasts/Language/sv/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast prenumerationer', + 'add' => 'Ny prenumeration', + 'view' => 'Visa prenumeration', + 'edit' => 'Ändra prenumeration', + 'regenerate_token' => 'Generera om token', + 'suspend' => 'Avaktivera prenumeration', + 'resume' => 'Återuppta prenumeration', + 'delete' => 'Radera prenumeration', + 'status' => [ + 'active' => 'Aktiv', + 'suspended' => 'Suspenderad', + 'expired' => 'Utgått', + ], + 'list' => [ + 'number' => 'Nummer', + 'email' => 'Epost', + 'expiration_date' => 'Utgångsdatum', + 'unlimited' => 'Obegränsat', + 'downloads' => 'Nerladdningar', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Epost', + 'expiration_date' => 'Utgångsdatum', + 'expiration_date_hint' => 'Datum och tid då prenumerationen går ut. Lämna tomt för ett obegränsat abonnemang.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Ändra prenumeration', + ], + 'form_link_add' => [ + 'link' => 'Länk för prenumerationssida', + 'link_hint' => 'Detta kommer att lägga till en uppmaning till åtgärder på webbplatsen som bjuder in lyssnare att prenumerera på podcasten.', + 'submit' => 'Spara länk', + ], + 'suspend_form' => [ + 'disclaimer' => 'Avstängning av abonnemanget kommer att begränsa abonnenten från att ha tillgång till premiuminnehållet. Du kommer fortfarande att kunna lyfta suspensionen efteråt.', + 'reason' => 'Orsak', + 'reason_placeholder' => 'Varför stänger du av prenumerationen?', + "submit" => 'Avaktivera prenumeration', + ], + 'delete_form' => [ + 'disclaimer' => 'Borttagning av {subscriber}s prenumeration kommer att ta bort all analysdata som är kopplad till den.', + 'understand' => 'Jag förstår, ta bort prenumerationen permanent', + 'submit' => 'Ta bort prenumeration', + ], + 'messages' => [ + 'addSuccess' => 'Ny prenumeration tillagd! Ett välkomstmeddelande skickades till {subscriber}.', + 'addError' => 'Prenumerationen kunde inte läggas till.', + 'editSuccess' => 'Prenumeration utgångsdatum uppdaterades! Ett e-postmeddelande skickades till {subscriber}.', + 'editError' => 'Prenumerationen kunde inte redigeras.', + 'regenerateTokenSuccess' => 'Token regenererad! Ett e-postmeddelande skickades till {subscriber} med den nya token.', + 'regenerateTokenError' => 'Token kunde inte regenereras.', + 'deleteSuccess' => 'Prenumerationen har tagits bort! Ett e-postmeddelande har skickats till {subscriber}.', + 'deleteError' => 'Prenumerationen kunde inte tas bort.', + 'suspendSuccess' => 'Prenumerationen suspenderades! Ett e-postmeddelande skickades till {subscriber}.', + 'suspendError' => 'Prenumerationen kunde inte stängas av.', + 'resumeSuccess' => 'Prenumerationen återupptades! Ett e-postmeddelande skickades till {subscriber}.', + 'resumeError' => 'Prenumerationen kunde inte återupptas.', + 'linkSaveSuccess' => 'Prenumerationslänken har sparats! Den kommer att visas på webbplatsen som en Call To Action!', + 'linkRemoveSuccess' => 'Prenumerationslänken har tagits bort!', + ], + 'emails' => [ + 'greeting' => 'Hej,', + 'token' => 'Din token: {0}', + 'unique_feed_link' => 'Din unika flödeslänk: {0}', + 'how_to_use' => 'Hur gör man?', + 'two_ways' => 'Du har två sätt att låsa upp premiumavsnitt:', + 'import_into_app' => 'Kopiera din unika feed url inuti din favorit podcast-app (importera den som ett privat flöde för att förhindra att du exponerar dina referenser).', + 'go_to_website' => 'Gå till {podcastWebsite}s webbplats och lås upp podcasten med din token.', + 'welcome_subject' => 'Välkommen till {podcastTitle}', + 'welcome' => 'Du har prenumererat på {podcastTitle}, tack och välkommen ombord!', + 'welcome_token_title' => 'Här är dina referenser för att låsa upp podcastens premiumavsnitt:', + 'welcome_expires' => 'Ditt abonnemang var inställt på att löpa ut {0}.', + 'welcome_never_expires' => 'Din prenumeration var inställd på att aldrig upphöra.', + 'reset_subject' => 'Din token återställdes!', + 'reset_token' => 'Din åtkomst till {podcastTitle} har återställts!', + 'reset_token_title' => 'Nya autentiseringsuppgifter har skapats för att du ska kunna låsa upp podcastens premiumavsnitt:', + 'edited_subject' => 'Din prenumeration har uppdaterats!', + 'edited_expires' => 'Ditt abonnemang för {podcastTitle} sattes att löpa ut den {expiresAt}.', + 'edited_never_expires' => 'Din prenumeration på {podcastTitle} har ställts in på att aldrig upphör!', + 'suspended_subject' => 'Din prenumeration har stängts av!', + 'suspended' => 'Din prenumeration på {podcastTitle} har stängts av! Du kan inte längre komma åt podcastens premiumavsnitt.', + 'suspended_reason' => 'Det är av följande skäl: {0}', + 'resumed_subject' => 'Din prenumeration har återupptagits!', + 'resumed' => 'Din prenumeration på {podcastTitle} har återupptagits! Du kan komma åt podcastens premiumavsnitt igen.', + 'deleted_subject' => 'Din prenumeration har tagits bort!', + 'deleted' => 'Din prenumeration på {podcastTitle} har tagits bort! Du har inte längre tillgång till podcastens premiumavsnitt.', + 'footer' => '{castopod} hostas på {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/uk/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/uk/PremiumPodcasts.php new file mode 100644 index 00000000..bd87ddae --- /dev/null +++ b/modules/PremiumPodcasts/Language/uk/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Подкаст містить преміум-епізоди', + 'episode_is_premium' => 'Цей подкаст містить преміум епізоди, тільки для преміум підписників', + 'unlock_episode' => 'Цей епізод призначений тільки для преміум підписників. Натисніть, щоб розблокувати його!', + 'banner_unlock' => 'Цей подкаст містить преміум епізоди, тільки для преміум підписників.', + 'banner_lock' => 'Подкаст був успішно розблокований! Насолоджуйтесь преміум епізодами!', + 'subscribe' => 'Підписатися', + 'lock' => 'Заблокувати', + 'unlock' => 'Розблокувати', + 'unlock_form' => [ + 'title' => 'Преміум контент', + 'subtitle' => 'Цей подкаст містить заблоковані преміум епізоди! Ви маєте ключ для їх розблокування?', + 'token' => 'Введіть ваш ключ', + 'token_hint' => 'Якщо ви підписані на {podcastTitle}, ви можете скопіювати ключ, відправлений вам на електрону пошту та вставити його тут.', + 'submit' => 'Розблокувати всі серії!', + 'call_to_action' => 'Розблокувати всі серії з {podcastTitle}:', + 'subscribe_cta' => 'Підписатися зараз!', + ], + 'messages' => [ + 'unlockSuccess' => 'Подкаст був успішно розблокований! Насолоджуйтесь преміум епізодами!', + 'unlockBadAttempt' => 'Здається, ваш ключ не працює…', + 'lockSuccess' => 'Подкаст успішно заблокований!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/uk/Subscription.php b/modules/PremiumPodcasts/Language/uk/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/uk/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/zh-hans/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/zh-hans/PremiumPodcasts.php new file mode 100644 index 00000000..8723a611 --- /dev/null +++ b/modules/PremiumPodcasts/Language/zh-hans/PremiumPodcasts.php @@ -0,0 +1,34 @@ + '播客包含优质剧集', + 'episode_is_premium' => '剧集是高级内容,仅适用于高级订阅者', + 'unlock_episode' => '本集仅适用于高级订阅者。 点击解锁!', + 'banner_unlock' => '此播客包含高级剧集,仅供高级订阅者使用。', + 'banner_lock' => '播客已解锁,享受优质剧集!', + 'subscribe' => '订阅', + 'lock' => '锁定', + 'unlock' => '解锁', + 'unlock_form' => [ + 'title' => '高级内容', + 'subtitle' => '此播客包含锁定的高级剧集! 你有解锁它们的秘钥吗?', + 'token' => '输入你的密钥', + 'token_hint' => '如果你订阅了 {podcastTitle},可以复制通过电子邮件发送给你的密钥并将其粘贴到此处。', + 'submit' => '解锁所有剧集!', + 'call_to_action' => '解锁 {podcastTitle} 的所有剧集:', + 'subscribe_cta' => '现在订阅 !', + ], + 'messages' => [ + 'unlockSuccess' => '播客已成功解锁! 享受优质剧集!', + 'unlockBadAttempt' => '你的密钥似乎不起作用...', + 'lockSuccess' => '播客已成功锁定!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/zh-hans/Subscription.php b/modules/PremiumPodcasts/Language/zh-hans/Subscription.php new file mode 100644 index 00000000..7b8e3d5b --- /dev/null +++ b/modules/PremiumPodcasts/Language/zh-hans/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => '新订阅', + 'view' => '查看订阅', + 'edit' => '编辑订阅', + 'regenerate_token' => '重新生成令牌', + 'suspend' => '停止订阅', + 'resume' => '恢复订阅', + 'delete' => '删除订阅', + 'status' => [ + 'active' => '活动', + 'suspended' => '已暂停', + 'expired' => '已过期', + ], + 'list' => [ + 'number' => '编号', + 'email' => '邮箱', + 'expiration_date' => '到期日', + 'unlimited' => '无限制', + 'downloads' => '下载', + 'status' => '状态', + ], + 'form' => [ + 'email' => '邮箱', + 'expiration_date' => '到期日', + 'expiration_date_hint' => '订阅到期的日期和时间。 留空时没有订阅限制。', + 'submit_create' => 'Create subscription', + 'submit_edit' => '编辑订阅', + ], + 'form_link_add' => [ + 'link' => '订阅页面链接', + 'link_hint' => '在网站中添加号召性用语,邀请听众订阅播客。', + 'submit' => '保存链接', + ], + 'suspend_form' => [ + 'disclaimer' => '暂停订阅将限制订阅者访问高级内容。你仍然可以在之后取消暂停。', + 'reason' => '原因', + 'reason_placeholder' => '您为什么要暂停订阅?', + "submit" => '暂停订阅', + ], + 'delete_form' => [ + 'disclaimer' => '删除 {subscriber} 的订阅将删除所有相关的分析数据。', + 'understand' => '我明白,永久删除订阅', + 'submit' => '移除订阅', + ], + 'messages' => [ + 'addSuccess' => '添加了新订阅! 欢迎电子邮件已发送给 {subscriber}。', + 'addError' => '无法添加订阅。', + 'editSuccess' => '订阅到期日期已更新! 一封电子邮件已发送给 {subscriber}。', + 'editError' => '无法添加订阅。', + 'regenerateTokenSuccess' => '重新生成令牌! 一封带有新令牌的电子邮件已发送给 {subscriber}。', + 'regenerateTokenError' => '无法重新生成令牌。', + 'deleteSuccess' => '订阅已删除! 一封电子邮件已发送给 {subscriber}。', + 'deleteError' => '无法删除订阅。', + 'suspendSuccess' => '订阅已暂停! 一封电子邮件已发送给 {subscriber}。', + 'suspendError' => '无法暂停订阅。', + 'resumeSuccess' => '订阅已恢复! 一封电子邮件已发送给 {subscriber}。', + 'resumeError' => '无法恢复订阅。', + 'linkSaveSuccess' => '订阅链接保存成功! 它将作为号召性用语出现在网站上!', + 'linkRemoveSuccess' => '订阅链接已成功删除!', + ], + 'emails' => [ + 'greeting' => '嘿,', + 'token' => '你的令牌: {0}', + 'unique_feed_link' => '你唯一的摘要链接:{0}', + 'how_to_use' => '如何使用?', + 'two_ways' => '你有两种解锁高级剧集的方法:', + 'import_into_app' => '在你最喜欢的播客应用程序中复制你唯一的摘要 URL(将其作为私人源导入以防止暴露你的凭据)。', + 'go_to_website' => '访问 {podcastWebsite} 的网站并使用你的令牌解锁播客。', + 'welcome_subject' => '欢迎来到 {podcastTitle}', + 'welcome' => '你已订阅 {podcastTitle},谢谢,欢迎加入!', + 'welcome_token_title' => '这是你解锁播客高级剧集的凭据:', + 'welcome_expires' => '你的订阅已设置为在 {0} 到期。', + 'welcome_never_expires' => '你的订阅设置为永不过期。', + 'reset_subject' => '你的令牌已重置!', + 'reset_token' => '你对 {podcastTitle} 的访问权限已重置!', + 'reset_token_title' => '已为你生成解锁播客高级剧集的新凭据:', + 'edited_subject' => '你的订阅已更新!', + 'edited_expires' => '你对 {podcastTitle} 的订阅已设置为在 {expiresAt} 到期。', + 'edited_never_expires' => '你对 {podcastTitle} 的订阅设置为永不过期!', + 'suspended_subject' => '你的订阅已被暂停!', + 'suspended' => '你的 {podcastTitle} 订阅已暂停! 你已无法再访问播客的高级剧集。', + 'suspended_reason' => '原因如下:{0}', + 'resumed_subject' => '你的订阅已恢复!', + 'resumed' => '你对 {podcastTitle} 的订阅已恢复! 你可以再次访问播客的高级剧集。', + 'deleted_subject' => '你的订阅已被删除!', + 'deleted' => '你对 {podcastTitle} 的订阅已被删除! 你无法再访问播客的高级剧集。', + 'footer' => '{castopod} 托管在 {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Language/zh-hant/PremiumPodcasts.php b/modules/PremiumPodcasts/Language/zh-hant/PremiumPodcasts.php new file mode 100644 index 00000000..18c0dd4e --- /dev/null +++ b/modules/PremiumPodcasts/Language/zh-hant/PremiumPodcasts.php @@ -0,0 +1,34 @@ + 'Podcast contains premium episodes', + 'episode_is_premium' => 'Episode is premium, only available to premium subscribers', + 'unlock_episode' => 'This episode is for premium subscribers only. Click to unlock it!', + 'banner_unlock' => 'This podcast contains premium episodes, only available to premium subscribers.', + 'banner_lock' => 'Podcast is unlocked, enjoy the premium episodes!', + 'subscribe' => 'Subscribe', + 'lock' => 'Lock', + 'unlock' => 'Unlock', + 'unlock_form' => [ + 'title' => 'Premium content', + 'subtitle' => 'This podcast contains locked premium episodes! Do you have the key to unlock them?', + 'token' => 'Enter your key', + 'token_hint' => 'If you are subscribed to {podcastTitle}, you may copy the key that was sent to you via email and paste it here.', + 'submit' => 'Unlock all episodes!', + 'call_to_action' => 'Unlock all episodes of {podcastTitle}:', + 'subscribe_cta' => 'Subscribe now!', + ], + 'messages' => [ + 'unlockSuccess' => 'Podcast was successfully unlocked! Enjoy the premium episodes!', + 'unlockBadAttempt' => 'Your key does not seem to be working…', + 'lockSuccess' => 'Podcast was successfully locked!', + ], +]; diff --git a/modules/PremiumPodcasts/Language/zh-hant/Subscription.php b/modules/PremiumPodcasts/Language/zh-hant/Subscription.php new file mode 100644 index 00000000..e83f0cb2 --- /dev/null +++ b/modules/PremiumPodcasts/Language/zh-hant/Subscription.php @@ -0,0 +1,100 @@ + 'Podcast subscriptions', + 'add' => 'New subscription', + 'view' => 'View subscription', + 'edit' => 'Edit subscription', + 'regenerate_token' => 'Regenerate token', + 'suspend' => 'Suspend subscription', + 'resume' => 'Resume subscription', + 'delete' => 'Delete subscription', + 'status' => [ + 'active' => 'Active', + 'suspended' => 'Suspended', + 'expired' => 'Expired', + ], + 'list' => [ + 'number' => 'Number', + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'unlimited' => 'Unlimited', + 'downloads' => 'Downloads', + 'status' => 'Status', + ], + 'form' => [ + 'email' => 'Email', + 'expiration_date' => 'Expiration date', + 'expiration_date_hint' => 'The date and time at which the subscription expires. Leave empty for an unlimited subscription.', + 'submit_create' => 'Create subscription', + 'submit_edit' => 'Edit subscription', + ], + 'form_link_add' => [ + 'link' => 'Subscription page link', + 'link_hint' => 'This will add a call to action in the website inviting listeners to subscribe to the podcast.', + 'submit' => 'Save link', + ], + 'suspend_form' => [ + 'disclaimer' => 'Suspending the subscription will restrict the subscriber from having access to the premium content. You will still be able to lift the suspension afterwards.', + 'reason' => 'Reason', + 'reason_placeholder' => 'Why are you suspending the subscription?', + "submit" => 'Suspend subscription', + ], + 'delete_form' => [ + 'disclaimer' => 'Deleting {subscriber}\'s subscription will remove all analytics data associated with it.', + 'understand' => 'I understand, remove the subscription permanently', + 'submit' => 'Remove subscription', + ], + 'messages' => [ + 'addSuccess' => 'New subscription added! A welcome email was sent to {subscriber}.', + 'addError' => 'Subscription could not be added.', + 'editSuccess' => 'Subscription expiry date was updated! An email was sent to {subscriber}.', + 'editError' => 'Subscription could not be edited.', + 'regenerateTokenSuccess' => 'Token regenerated! An email was sent to {subscriber} with the new token.', + 'regenerateTokenError' => 'Token could not be regenerated.', + 'deleteSuccess' => 'Subscription was removed! An email was sent to {subscriber}.', + 'deleteError' => 'Subscription could not be removed.', + 'suspendSuccess' => 'Subscription was suspended! An email was sent to {subscriber}.', + 'suspendError' => 'Subscription could not be suspended.', + 'resumeSuccess' => 'Subscription was resumed! An email was sent to {subscriber}.', + 'resumeError' => 'Subscription could not be resumed.', + 'linkSaveSuccess' => 'Subscription link was saved successfully! It will appear in the website as a Call To Action!', + 'linkRemoveSuccess' => 'Subscription link was removed successfully!', + ], + 'emails' => [ + 'greeting' => 'Hey,', + 'token' => 'Your token: {0}', + 'unique_feed_link' => 'Your unique feed link: {0}', + 'how_to_use' => 'How to use?', + 'two_ways' => 'You have two ways of unlocking the premium episodes:', + 'import_into_app' => 'Copy your unique feed url inside your favourite podcast app (import it as a private feed to prevent exposing your credentials).', + 'go_to_website' => 'Go to {podcastWebsite}\'s website and unlock the podcast with your token.', + 'welcome_subject' => 'Welcome to {podcastTitle}', + 'welcome' => 'You have subscribed to {podcastTitle}, thank you and welcome aboard!', + 'welcome_token_title' => 'Here are your credentials to unlock the podcast\'s premium episodes:', + 'welcome_expires' => 'Your subscription was set to expire on {0}.', + 'welcome_never_expires' => 'Your subscription was set to never expire.', + 'reset_subject' => 'Your token was reset!', + 'reset_token' => 'Your access to {podcastTitle} has been reset!', + 'reset_token_title' => 'New credentials have been generated for you to unlock the podcast\'s premium episodes:', + 'edited_subject' => 'Your subscription has been updated!', + 'edited_expires' => 'Your subscription for {podcastTitle} was set to expire on {expiresAt}.', + 'edited_never_expires' => 'Your subscription for {podcastTitle} was set to never expire!', + 'suspended_subject' => 'Your subscription has been suspended!', + 'suspended' => 'Your subscription for {podcastTitle} has been suspended! You can no longer access the podcast\'s premium episodes.', + 'suspended_reason' => 'That is for the following reason: {0}', + 'resumed_subject' => 'Your subscription has been resumed!', + 'resumed' => 'Your subscription for {podcastTitle} has been resumed! You may access the podcast\'s premium episodes again.', + 'deleted_subject' => 'Your subscription has been removed!', + 'deleted' => 'Your subscription for {podcastTitle} has been removed! You no longer have access to the podcast\'s premium episodes.', + 'footer' => '{castopod} hosted on {host}', + ], +]; diff --git a/modules/PremiumPodcasts/Models/SubscriptionModel.php b/modules/PremiumPodcasts/Models/SubscriptionModel.php new file mode 100644 index 00000000..32619b19 --- /dev/null +++ b/modules/PremiumPodcasts/Models/SubscriptionModel.php @@ -0,0 +1,151 @@ + + */ + protected $allowedFields = [ + 'id', + 'podcast_id', + 'email', + 'token', + 'status', + 'status_message', + 'expires_at', + 'created_by', + 'updated_by', + ]; + + protected $returnType = Subscription::class; + + /** + * @var bool + */ + protected $useSoftDeletes = false; + + /** + * @var bool + */ + protected $useTimestamps = true; + + /** + * @var list + */ + protected $afterInsert = ['clearCache']; + + /** + * @var list + */ + protected $afterUpdate = ['clearCache']; + + /** + * @var list + */ + protected $beforeDelete = ['clearCache']; + + public function getSubscriptionById(int $subscriptionId): ?Subscription + { + $cacheName = "subscription#{$subscriptionId}"; + if (! ($found = cache($cacheName))) { + $found = $this->find($subscriptionId); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @return Subscription[] + */ + public function getPodcastSubscriptions(int $podcastId): array + { + $cacheName = "podcast#{$podcastId}_subscriptions"; + if (! ($found = cache($cacheName))) { + $found = $this->where('podcast_id', $podcastId) + ->findAll(); + + cache() + ->save($cacheName, $found, DECADE); + } + + return $found; + } + + /** + * @param string $token plain-text token to be encrypted and matched against encrypted tokens in database + */ + public function validateSubscription(int|string $podcastIdOrHandle, string $token): ?Subscription + { + $subscriptionModel = $this; + + if (is_int($podcastIdOrHandle)) { + $this->where('id', $podcastIdOrHandle); + } else { + $this->select('subscriptions.*') + ->where('handle', $podcastIdOrHandle) + ->join('podcasts', 'podcasts.id = subscriptions.podcast_id'); + } + + return $subscriptionModel + ->where([ + 'token' => hash('sha256', $token), + 'status' => 'active', + ]) + ->groupStart() + ->where('expires_at') + ->orWhere('`expires_at` > UTC_TIMESTAMP()', null, false) + ->groupEnd() + ->first(); + } + + /** + * @param mixed[] $data + * + * @return mixed[] + */ + protected function clearCache(array $data): array + { + /** @var ?Subscription */ + $subscription = new self() + ->find(is_array($data['id']) ? $data['id'][0] : $data['id']); + + if (! $subscription instanceof Subscription) { + return $data; + } + + cache() + ->delete("subscription#{$subscription->id}"); + cache() + ->delete("podcast#{$subscription->podcast_id}_subscriptions"); + + return $data; + } +} diff --git a/modules/PremiumPodcasts/PremiumPodcasts.php b/modules/PremiumPodcasts/PremiumPodcasts.php new file mode 100644 index 00000000..036b6f05 --- /dev/null +++ b/modules/PremiumPodcasts/PremiumPodcasts.php @@ -0,0 +1,114 @@ + + */ + protected $subscriptions = []; + + public function setSubscriptionModel(SubscriptionModel $subscriptionModel): self + { + $this->subscriptionModel = $subscriptionModel; + + return $this; + } + + public function unlock(string $podcastHandle, string $token): bool + { + $subscription = $this->subscriptionModel->validateSubscription($podcastHandle, $token); + + if (! $subscription instanceof Subscription) { + $this->subscriptions[$podcastHandle] = null; + + return false; + } + + $this->subscriptions[$podcastHandle] = $subscription; + + $session = session(); + $session->set("{$podcastHandle}:subscription", $subscription); + + Events::trigger('unlock', $podcastHandle, $subscription); + + return true; + } + + public function lock(string $podcastHandle): bool + { + if (! $this->isUnlocked($podcastHandle)) { + return true; + } + + $this->subscriptions[$podcastHandle] = null; + + unset($_SESSION["{$podcastHandle}:subscription"]); + + Events::trigger('lock', $podcastHandle); + + return true; + } + + public function isUnlocked(string $podcastHandle): bool + { + if (array_key_exists( + $podcastHandle, + $this->subscriptions, + ) && ($this->subscriptions[$podcastHandle] instanceof Subscription)) { + return true; + } + + if ($subscription = session()->get("{$podcastHandle}:subscription")) { + $this->subscriptions[$podcastHandle] = $subscription; + + return true; + } + + return false; + } + + public function check(string $podcastHandle): bool + { + // check if locked, no need to go any further + if (! $this->isUnlocked($podcastHandle)) { + return false; + } + + // Store the current subscription object + $this->subscriptions[$podcastHandle] = $this->subscriptionModel->getSubscriptionById( + $this->subscriptions[$podcastHandle]->id, + ); + + if (! $this->subscriptions[$podcastHandle] instanceof Subscription) { + return false; + } + + // lock podcast if subscription is not active + if ($this->subscriptions[$podcastHandle]->status !== 'active') { + $this->lock($podcastHandle); + + return false; + } + + // All good! + return true; + } + + /** + * Returns the Subscription instance for the current logged in user. + */ + public function subscription(string $podcastHandle): ?Subscription + { + return $this->isUnlocked($podcastHandle) ? $this->subscriptions[$podcastHandle] : null; + } +} diff --git a/modules/Update/Commands/DatabaseUpdate.php b/modules/Update/Commands/DatabaseUpdate.php new file mode 100644 index 00000000..380f5305 --- /dev/null +++ b/modules/Update/Commands/DatabaseUpdate.php @@ -0,0 +1,35 @@ +setNamespace(null) + ->latest(); + } +} diff --git a/modules/WebSub/Commands/Publish.php b/modules/WebSub/Commands/Publish.php new file mode 100644 index 00000000..c0f47b22 --- /dev/null +++ b/modules/WebSub/Commands/Publish.php @@ -0,0 +1,97 @@ +builder() + ->select('podcasts.*') + ->distinct() + ->join('episodes', 'podcasts.id = episodes.podcast_id', 'left outer') + ->where('podcasts.is_published_on_hubs', false) + ->where('`' . $podcastModel->db->getPrefix() . 'podcasts`.`published_at` <= UTC_TIMESTAMP()', null, false) + ->orGroupStart() + ->where('episodes.is_published_on_hubs', false) + ->where('`' . $podcastModel->db->getPrefix() . 'episodes`.`published_at` <= UTC_TIMESTAMP()', null, false) + ->groupEnd(); + $podcasts = $podcastModel->findAll(); + + if ($podcasts === []) { + return; + } + + /** @var CURLRequest $request */ + $request = service('curlrequest'); + + $requestOptions = [ + 'headers' => [ + 'User-Agent' => 'Castopod/' . CP_VERSION . '; +' . base_url('', 'https'), + 'Content-Type' => 'application/x-www-form-urlencoded', + ], + ]; + + $hubUrls = config('WebSub') + ->hubs; + + foreach ($podcasts as $podcast) { + $requestOptions['form_params'] = [ + 'hub.mode' => 'publish', + 'hub.url' => $podcast->feed_url, + ]; + + foreach ($hubUrls as $hub) { + try { + $request->post($hub, $requestOptions); + } catch (Exception $exception) { + log_message( + 'warning', + "COULD NOT PUBLISH @{$podcast->handle} ON {$hub}" . PHP_EOL . $exception->getMessage(), + ); + } + } + + // set podcast feed as having been pushed onto hubs + new PodcastModel() + ->update($podcast->id, [ + 'is_published_on_hubs' => 1, + ]); + + // set newly published episodes as pushed onto hubs + new EpisodeModel() + ->set('is_published_on_hubs', true) + ->where([ + 'podcast_id' => $podcast->id, + 'is_published_on_hubs' => false, + ]) + ->where('`published_at` <= UTC_TIMESTAMP()', null, false) + ->update(); + } + } +} diff --git a/modules/WebSub/Config/WebSub.php b/modules/WebSub/Config/WebSub.php new file mode 100644 index 00000000..745a0eb1 --- /dev/null +++ b/modules/WebSub/Config/WebSub.php @@ -0,0 +1,23 @@ +forge->addColumn('podcasts', [ + 'is_published_on_hubs' => [ + 'type' => 'BOOLEAN', + 'null' => false, + 'default' => 0, + 'after' => 'custom_rss', + ], + ]); + } + + #[Override] + public function down(): void + { + $this->forge->dropColumn('podcasts', 'is_published_on_hubs'); + } +} diff --git a/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php b/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php new file mode 100644 index 00000000..b57be027 --- /dev/null +++ b/modules/WebSub/Database/Migrations/2022-03-07-181500_add_is_published_on_hubs_to_episodes.php @@ -0,0 +1,36 @@ +forge->addColumn('episodes', [ + 'is_published_on_hubs' => [ + 'type' => 'BOOLEAN', + 'null' => false, + 'default' => 0, + 'after' => 'custom_rss', + ], + ]); + } + + #[Override] + public function down(): void + { + $this->forge->dropColumn('episodes', 'is_published_on_hubs'); + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 36dccf63..00000000 --- a/package-lock.json +++ /dev/null @@ -1,41797 +0,0 @@ -{ - "name": "castopod-host", - "version": "1.0.0-alpha.80", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "castopod-host", - "version": "1.0.0-alpha.80", - "license": "AGPL-3.0-or-later", - "dependencies": { - "@amcharts/amcharts4": "^4.10.17", - "@amcharts/amcharts4-geodata": "^4.1.19", - "@popperjs/core": "^2.9.1", - "@rollup/plugin-multi-entry": "^4.0.0", - "choices.js": "^9.0.1", - "flatpickr": "^4.6.9", - "leaflet": "^1.7.1", - "leaflet.markercluster": "^1.5.1", - "lit": "^2.0.0-rc.2", - "prosemirror-example-setup": "^1.1.2", - "prosemirror-markdown": "^1.5.1", - "prosemirror-state": "^1.3.4", - "prosemirror-view": "^1.18.1" - }, - "devDependencies": { - "@commitlint/cli": "^12.0.1", - "@commitlint/config-conventional": "^12.0.1", - "@semantic-release/changelog": "^6.0.1", - "@semantic-release/exec": "^6.0.2", - "@semantic-release/git": "^10.0.1", - "@semantic-release/gitlab": "^7.0.4", - "@tailwindcss/forms": "^0.2.1", - "@tailwindcss/line-clamp": "^0.2.0", - "@tailwindcss/typography": "^0.4.0", - "@types/leaflet": "^1.7.5", - "@types/prosemirror-markdown": "^1.5.1", - "@types/prosemirror-view": "^1.17.1", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "cpy-cli": "^3.1.1", - "cross-env": "^7.0.3", - "cssnano": "^4.1.10", - "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.22.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-prettier": "^3.3.1", - "husky": "^6.0.0", - "is-ci": "^3.0.0", - "lint-staged": "^10.5.4", - "postcss-import": "^14.0.0", - "postcss-preset-env": "^6.7.0", - "prettier": "2.2.1", - "prettier-plugin-organize-imports": "^1.1.1", - "rollup-plugin-multi-input": "^1.2.0", - "semantic-release": "^18.0.0", - "stylelint": "^13.12.0", - "stylelint-config-standard": "^21.0.0", - "svgo": "^2.2.2", - "tailwindcss": "^2.2.4", - "typescript": "^4.2.3", - "vite": "^2.3.8", - "vite-plugin-ruby": "^2.0.4" - } - }, - "node_modules/@amcharts/amcharts4": { - "version": "4.10.22", - "resolved": "https://registry.npmjs.org/@amcharts/amcharts4/-/amcharts4-4.10.22.tgz", - "integrity": "sha512-Z/vPGKtNf1m4sdKK1P4San8SAG1AuYJ0tLhptUqntb4u+kRfRbU2QydIGsVmpHPENLg17ukIWySwo6mv3by/tw==", - "dependencies": { - "@babel/runtime": "^7.6.3", - "core-js": "^3.0.0", - "d3-force": "^2.0.1", - "d3-geo": "^2.0.1", - "d3-geo-projection": "^3.0.0", - "pdfmake": "^0.2.2", - "polylabel": "^1.0.2", - "raf": "^3.4.1", - "regression": "^2.0.1", - "rgbcolor": "^1.0.1", - "stackblur-canvas": "^2.0.0", - "tslib": "^2.0.1", - "venn.js": "^0.2.20", - "xlsx": "^0.17.0" - } - }, - "node_modules/@amcharts/amcharts4-geodata": { - "version": "4.1.19", - "resolved": "https://registry.npmjs.org/@amcharts/amcharts4-geodata/-/amcharts4-geodata-4.1.19.tgz", - "integrity": "sha512-y100J6mp8H95qfHPPmeAat8oC+VXJrpt+rnwOt554sEW6cFCWY6BKgPKL2dVlVbnz0U3dqNsyENOqXmp3Pu7vg==" - }, - "node_modules/@amcharts/amcharts4/node_modules/tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" - }, - "node_modules/@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", - "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.1" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", - "dev": true - }, - "node_modules/@babel/core": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.10.tgz", - "integrity": "sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.10", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.10", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/core/node_modules/@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/core/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz", - "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz", - "integrity": "sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", - "dev": true - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", - "dev": true - }, - "node_modules/@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", - "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.1", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.12.tgz", - "integrity": "sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/template/node_modules/@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/template/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/traverse/node_modules/@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/traverse/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", - "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/@babel/types/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@commitlint/cli": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-12.0.1.tgz", - "integrity": "sha512-V+cMYNHJOr40XT9Kvz3Vrz1Eh7QE1rjQrUbifawDAqcOrBJFuoXwU2SAcRtYFCSqFy9EhbreQGhZFs8dYb90KA==", - "dev": true, - "dependencies": { - "@commitlint/format": "^12.0.1", - "@commitlint/lint": "^12.0.1", - "@commitlint/load": "^12.0.1", - "@commitlint/read": "^12.0.1", - "@commitlint/types": "^12.0.1", - "get-stdin": "8.0.0", - "lodash": "^4.17.19", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", - "yargs": "^16.2.0" - }, - "bin": { - "commitlint": "cli.js" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/cli/node_modules/@commitlint/execute-rule": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-12.0.1.tgz", - "integrity": "sha512-JzyweYfZlFLtXpgP+btzSY3YAkGPg61TqUSYQqBr4+5IaVf1FruMm5v4D5eLu9dAJuNKUfHbM3AEfuEPiZ79pg==", - "dev": true, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/cli/node_modules/@commitlint/load": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-12.0.1.tgz", - "integrity": "sha512-dX8KdCWn7w0bTkkk3zKQpe9X8vsTRa5EM+1ffF313wCX9b6tGa9vujhEHCkSzKAbbE2tFV64CHZygE7rtlHdIA==", - "dev": true, - "dependencies": { - "@commitlint/execute-rule": "^12.0.1", - "@commitlint/resolve-extends": "^12.0.1", - "@commitlint/types": "^12.0.1", - "chalk": "^4.0.0", - "cosmiconfig": "^7.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-12.0.1.tgz", - "integrity": "sha512-Mvg0GDi/68Cqw893ha8uhxE8myHfPmiSSSi7d1x4VJNR4hoS37lBdX89kyx4i9NPmLfviY2cUJKTyK8ZrFznZw==", - "dev": true, - "dependencies": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/cli/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/cli/node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "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/@commitlint/cli/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/cli/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/@commitlint/cli/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" - } - }, - "node_modules/@commitlint/cli/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/@commitlint/config-conventional": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-12.0.1.tgz", - "integrity": "sha512-1ZhB135lh47zVmf1orwcjxuKuam11fJIH/bdVxW9XiQv8XPwC6iIp19knfl8FcOT78AVBnes1z6EVxgUeP2/4Q==", - "dev": true, - "dependencies": { - "conventional-changelog-conventionalcommits": "^4.3.1" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/ensure": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-12.0.1.tgz", - "integrity": "sha512-XdBq+q1YBBDxWIAEjE3Y1YMbzhUnUuSLAEWD8SU1xsvEpQXWRYwDlMBRkjO7funNWTdL0ZQSkZDzme70imYjbw==", - "dev": true, - "dependencies": { - "@commitlint/types": "^12.0.1", - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/ensure/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/execute-rule": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-9.1.2.tgz", - "integrity": "sha512-NGbeo0KCVYo1yj9vVPFHv6RGFpIF6wcQxpFYUKGIzZVV9Vz1WyiKS689JXa99Dt1aN0cZlEJJLnTNDIgYls0Vg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=v8.17.0" - } - }, - "node_modules/@commitlint/format": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-12.0.1.tgz", - "integrity": "sha512-rF79ipAxR8yFzPzG5tRoEZ//MRkyxCXj4JhpEjtdaCMBAXMssI8uazn3e5D8z4UFgSDe9qOnL0OmQvql7HTMoA==", - "dev": true, - "dependencies": { - "@commitlint/types": "^12.0.1", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/format/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/is-ignored": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-12.0.1.tgz", - "integrity": "sha512-AplfLn5mX/kWTIiSolcOhTYcgphuGLX8FUr+HmyHBEqUkO36jt0z9caysH47fqU71ePtH63v1DWm+RYQ5RPDjg==", - "dev": true, - "dependencies": { - "@commitlint/types": "^12.0.1", - "semver": "7.3.4" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/is-ignored/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/is-ignored/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@commitlint/lint": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-12.0.1.tgz", - "integrity": "sha512-1lKyRCq4ahJrY+Xxo8LsqCbALeJkodtEfpmYHeA5HpPMnK7lRSplLqOLcTCjoPfd4vO+gl6aDEZN+ow3YGQBOg==", - "dev": true, - "dependencies": { - "@commitlint/is-ignored": "^12.0.1", - "@commitlint/parse": "^12.0.1", - "@commitlint/rules": "^12.0.1", - "@commitlint/types": "^12.0.1" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/lint/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/load": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-9.1.2.tgz", - "integrity": "sha512-FPL82xBuF7J3EJ57kLVoligQP4BFRwrknooP+vNT787AXmQ/Fddc/iYYwHwy67pNkk5N++/51UyDl/CqiHb6nA==", - "dev": true, - "optional": true, - "dependencies": { - "@commitlint/execute-rule": "^9.1.2", - "@commitlint/resolve-extends": "^9.1.2", - "@commitlint/types": "^9.1.2", - "chalk": "4.1.0", - "cosmiconfig": "^6.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=v8.17.0" - } - }, - "node_modules/@commitlint/load/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "optional": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@commitlint/load/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, - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@commitlint/load/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, - "optional": true - }, - "node_modules/@commitlint/load/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "optional": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/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, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "optional": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/load/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, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@commitlint/load/node_modules/parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "optional": 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" - } - }, - "node_modules/@commitlint/load/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, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/load/node_modules/supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "optional": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/message": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-12.0.1.tgz", - "integrity": "sha512-fXuoxRC+NT1wEQi6p8oHfT7wvWIRgTk+udlRJnWTjmMpiYzVnMmmZfasdShirWr4TtxQtMyL+5DVgh7Y98kURw==", - "dev": true, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/parse": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-12.0.1.tgz", - "integrity": "sha512-7oEGASmzBnHir5jSIR7KephXrKh7rIi9a6RpH1tOT+CIENYvhe8EDtIy29qMt+RLa2LlaPF7YrAgaJRfzG0YDQ==", - "dev": true, - "dependencies": { - "@commitlint/types": "^12.0.1", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/parse/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/read": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-12.0.1.tgz", - "integrity": "sha512-baa0YeD4QOctEuthLpExQSi9xPiw0kDPfUVHqp8I88iuIXJECeS8S1+1GBiz89e8dLN9zmEE+sN9vtJHdAp9YA==", - "dev": true, - "dependencies": { - "@commitlint/top-level": "^12.0.1", - "@commitlint/types": "^12.0.1", - "fs-extra": "^9.0.0", - "git-raw-commits": "^2.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/read/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/read/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@commitlint/read/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "node_modules/@commitlint/read/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@commitlint/resolve-extends": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-9.1.2.tgz", - "integrity": "sha512-HcoL+qFGmWEu9VM4fY0HI+VzF4yHcg3x+9Hx6pYFZ+r2wLbnKs964y0v68oyMO/mS/46MVoLNXZGR8U3adpadg==", - "dev": true, - "optional": true, - "dependencies": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "engines": { - "node": ">=v8.17.0" - } - }, - "node_modules/@commitlint/resolve-extends/node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "optional": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@commitlint/resolve-extends/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, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@commitlint/resolve-extends/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, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@commitlint/rules": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-12.0.1.tgz", - "integrity": "sha512-A5O0ubNGugZR9WWxk5IVOLo07lpdUwhG5WkAW2lYpgZ7Z/2U4PLob9b4Ih1eHbQu+gnVeFr91k7F0DrpM7B8EQ==", - "dev": true, - "dependencies": { - "@commitlint/ensure": "^12.0.1", - "@commitlint/message": "^12.0.1", - "@commitlint/to-lines": "^12.0.1", - "@commitlint/types": "^12.0.1" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/rules/node_modules/@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/to-lines": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-12.0.1.tgz", - "integrity": "sha512-XwcJ1jY7x2fhudzbGMpNQkTSMVrxWrI8bRMbVe3Abuu7RfYpFf7VXAlhtnLfxBoagaK7RxjC2+eRidp/3txQBg==", - "dev": true, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/top-level": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-12.0.1.tgz", - "integrity": "sha512-rHdgt7U24GEau2/9i2vEAbksxkBRiVjHj5ECFL5dd0AJOIvaK++vMg4EF/ME0X/1yd9qVTHTNOl2Q4tTFK7VBQ==", - "dev": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=v10" - } - }, - "node_modules/@commitlint/top-level/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" - } - }, - "node_modules/@commitlint/top-level/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" - } - }, - "node_modules/@commitlint/top-level/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" - } - }, - "node_modules/@commitlint/top-level/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" - } - }, - "node_modules/@commitlint/types": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", - "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=v8.17.0" - } - }, - "node_modules/@csstools/convert-colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", - "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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" - } - }, - "node_modules/@eslint/eslintrc/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/@foliojs-fork/fontkit": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.1.tgz", - "integrity": "sha512-U589voc2/ROnvx1CyH9aNzOQWJp127JGU1QAylXGQ7LoEAF6hMmahZLQ4eqAcgHUw+uyW4PjtCItq9qudPkK3A==", - "dependencies": { - "@foliojs-fork/restructure": "^2.0.2", - "brfs": "^2.0.0", - "brotli": "^1.2.0", - "browserify-optional": "^1.0.1", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "^1.2.0", - "tiny-inflate": "^1.0.2", - "unicode-properties": "^1.2.2", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/@foliojs-fork/linebreak": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.1.tgz", - "integrity": "sha512-pgY/+53GqGQI+mvDiyprvPWgkTlVBS8cxqee03ejm6gKAQNsR1tCYCIvN9FHy7otZajzMqCgPOgC4cHdt4JPig==", - "dependencies": { - "base64-js": "1.3.1", - "brfs": "^2.0.2", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/@foliojs-fork/pdfkit": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.12.3.tgz", - "integrity": "sha512-WAMiL5Dp1EdHyuEeVphiqVeFEaccGShS5wLcuOXFF0wlBE5agkvTEk3sJ2OfAn87FaStpkuiaiSKNRexMlNHUA==", - "dependencies": { - "@foliojs-fork/fontkit": "^1.9.1", - "@foliojs-fork/linebreak": "^1.1.1", - "crypto-js": "^4.0.0", - "png-js": "^1.0.0" - } - }, - "node_modules/@foliojs-fork/restructure": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz", - "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==" - }, - "node_modules/@fullhuman/postcss-purgecss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-4.0.3.tgz", - "integrity": "sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==", - "dev": true, - "dependencies": { - "purgecss": "^4.0.3" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/@lit/reactive-element": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0-rc.2.tgz", - "integrity": "sha512-cujeIl5Ei8FC7UHf4/4Q3bRJOtdTe1vpJV/JEBYCggedmQ+2P8A2oz7eE+Vxi6OJ4nc0X+KZxXnBoH4QrEbmEQ==" - }, - "node_modules/@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "dependencies": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3" - } - }, - "node_modules/@octokit/core": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz", - "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", - "dev": true, - "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.0", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint/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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dev": true, - "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", - "dev": true - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.34.0" - }, - "peerDependencies": { - "@octokit/core": ">=2" - } - }, - "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.34.0", - "deprecation": "^2.3.1" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "node_modules/@octokit/request": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz", - "integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==", - "dev": true, - "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.1", - "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "node_modules/@octokit/request/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==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@octokit/rest": { - "version": "18.12.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", - "dev": true, - "dependencies": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" - } - }, - "node_modules/@octokit/types": { - "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", - "dev": true, - "dependencies": { - "@octokit/openapi-types": "^11.2.0" - } - }, - "node_modules/@popperjs/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", - "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==" - }, - "node_modules/@rollup/plugin-multi-entry": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.0.0.tgz", - "integrity": "sha512-1Sw86rwFxrNS7ECY3iSZ7T940xKnruNGpmQDgSDVTp+VTa1g5cPXNzBgp+IoOer41CiVeGFLwYwvicVoJLHEDQ==", - "dependencies": { - "@rollup/plugin-virtual": "^2.0.3", - "matched": "^5.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-virtual": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.0.3.tgz", - "integrity": "sha512-pw6ziJcyjZtntQ//bkad9qXaBx665SgEL8C8KI5wO8G5iU5MPxvdWrQyVaAvjojGm9tJoS8M9Z/EEepbqieYmw==", - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@semantic-release/changelog": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.1.tgz", - "integrity": "sha512-FT+tAGdWHr0RCM3EpWegWnvXJ05LQtBkQUaQRIExONoXjVjLuOILNm4DEKNaV+GAQyJjbLRVs57ti//GypH6PA==", - "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "fs-extra": "^9.0.0", - "lodash": "^4.17.4" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0" - } - }, - "node_modules/@semantic-release/changelog/node_modules/fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@semantic-release/changelog/node_modules/jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" - } - }, - "node_modules/@semantic-release/changelog/node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@semantic-release/commit-analyzer": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.1.tgz", - "integrity": "sha512-ncNsnrLmiykhgNZUXNvhhAjNN0me7VGIb0X5hu3ogyi5DDPapjGAHdEffO5vi+HX1BFWLRD/Ximx5PjGAKjAqQ==", - "dev": true, - "dependencies": { - "conventional-changelog-angular": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.0.7", - "debug": "^4.0.0", - "import-from": "^4.0.0", - "lodash": "^4.17.4", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/commit-analyzer/node_modules/import-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", - "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", - "dev": true, - "engines": { - "node": ">=12.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/commit-analyzer/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/@semantic-release/commit-analyzer/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/@semantic-release/commit-analyzer/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/@semantic-release/error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", - "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", - "dev": true, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/@semantic-release/exec": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-6.0.2.tgz", - "integrity": "sha512-ciaqJTHB1TFtU6C78xrgmoNI9UyfheR9+Bk6Ico7CJ7+ADOEAvUrPBKvz64UCfoWlg+SlKGTVGbFnA509wRUVw==", - "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "execa": "^5.0.0", - "lodash": "^4.17.4", - "parse-json": "^5.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0" - } - }, - "node_modules/@semantic-release/exec/node_modules/parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "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" - } - }, - "node_modules/@semantic-release/git": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", - "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", - "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "execa": "^5.0.0", - "lodash": "^4.17.4", - "micromatch": "^4.0.0", - "p-reduce": "^2.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0" - } - }, - "node_modules/@semantic-release/git/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/git/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/git/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/@semantic-release/git/node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@semantic-release/git/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/@semantic-release/github": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.2.tgz", - "integrity": "sha512-wIbfhOeuxlYzMTjtSAa2xgr54n7ZuPAS2gadyTWBpUt2PNAPgla7A6XxCXJnaKPgfVF0iFfSk3B+KlVKk6ByVg==", - "dev": true, - "dependencies": { - "@octokit/rest": "^18.0.0", - "@semantic-release/error": "^2.2.0", - "aggregate-error": "^3.0.0", - "bottleneck": "^2.18.1", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "issue-parser": "^6.0.0", - "lodash": "^4.17.4", - "mime": "^3.0.0", - "p-filter": "^2.0.0", - "p-retry": "^4.0.0", - "url-join": "^4.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" - } - }, - "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", - "dev": true - }, - "node_modules/@semantic-release/github/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@semantic-release/github/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@semantic-release/github/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/@semantic-release/github/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@semantic-release/github/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@semantic-release/gitlab": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@semantic-release/gitlab/-/gitlab-7.0.4.tgz", - "integrity": "sha512-TL6kT526+ir/uehMFdTlJNXUj+p+SjPAYUkit6lh5Rs8kxeHQ01bgmpYLQlc94ZDpy9x2Tzcb/NRwKojkmLG4A==", - "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "escape-string-regexp": "^3.0.0", - "form-data": "^4.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "got": "^11.0.0", - "lodash": "^4.17.11", - "parse-path": "^4.0.0", - "url-join": "^4.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0" - } - }, - "node_modules/@semantic-release/gitlab/node_modules/escape-string-regexp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-3.0.0.tgz", - "integrity": "sha512-11dXIUC3umvzEViLP117d0KN6LJzZxh5+9F4E/7WLAAw7GrHk8NpUR+g9iJi/pe9C0py4F8rs0hreyRCwlAuZg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@semantic-release/gitlab/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@semantic-release/gitlab/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@semantic-release/gitlab/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@semantic-release/gitlab/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@semantic-release/npm": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-8.0.3.tgz", - "integrity": "sha512-Qbg7x/O1t3sJqsv2+U0AL4Utgi/ymlCiUdt67Ftz9HL9N8aDML4t2tE0T9MBaYdqwD976hz57DqHHXKVppUBoA==", - "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.0", - "lodash": "^4.17.15", - "nerf-dart": "^1.0.0", - "normalize-url": "^6.0.0", - "npm": "^7.0.0", - "rc": "^1.2.8", - "read-pkg": "^5.0.0", - "registry-auth-token": "^4.0.0", - "semver": "^7.1.2", - "tempy": "^1.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0" - } - }, - "node_modules/@semantic-release/npm/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@semantic-release/npm/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@semantic-release/npm/node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@semantic-release/npm/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@semantic-release/npm/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@semantic-release/release-notes-generator": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.2.tgz", - "integrity": "sha512-I4eavIcDan8fNQHskZ2cbWkFMimvgxNkqR2UfuYNwYBgswEl3SJsN8XMf9gZWObt6nXDc2QfDwhjy8DjTZqS3w==", - "dev": true, - "dependencies": { - "conventional-changelog-angular": "^5.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.0.0", - "debug": "^4.0.0", - "get-stream": "^6.0.0", - "import-from": "^4.0.0", - "into-stream": "^6.0.0", - "lodash": "^4.17.4", - "read-pkg-up": "^7.0.0" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" - } - }, - "node_modules/@semantic-release/release-notes-generator/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/@semantic-release/release-notes-generator/node_modules/import-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", - "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", - "dev": true, - "engines": { - "node": ">=12.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@stylelint/postcss-css-in-js": { - "version": "0.37.2", - "resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz", - "integrity": "sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA==", - "dev": true, - "dependencies": { - "@babel/core": ">=7.9.0" - } - }, - "node_modules/@stylelint/postcss-markdown": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz", - "integrity": "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==", - "dev": true, - "dependencies": { - "remark": "^13.0.0", - "unist-util-find-all-after": "^3.0.2" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tailwindcss/forms": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.2.1.tgz", - "integrity": "sha512-czfvEdY+J2Ogfd6RUSr/ZSUmDxTujr34M++YLnp2cCPC3oJ4kFvFMaRXA6cEXKw7F1hJuapdjXRjsXIEXGgORg==", - "dev": true, - "dependencies": { - "mini-svg-data-uri": "^1.2.3" - } - }, - "node_modules/@tailwindcss/line-clamp": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.2.0.tgz", - "integrity": "sha512-+jXSdRK3/9V/BCPCr+iNpMMhxWMMv62vn/AS2b3/ClmueGuhCijW3bUwO1IiHnE7uCaF74Sli8jUCv9djwvpLg==", - "dev": true - }, - "node_modules/@tailwindcss/typography": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.4.0.tgz", - "integrity": "sha512-3BfOYT5MYNEq81Ism3L2qu/HRP2Q5vWqZtZRQqQrthHuaTK9qpuPfbMT5WATjAM5J1OePKBaI5pLoX4S1JGNMQ==", - "dev": true, - "dependencies": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@trysound/sax": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz", - "integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "node_modules/@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "node_modules/@types/geojson": { - "version": "7946.0.8", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", - "dev": true - }, - "node_modules/@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/highlight.js": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", - "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", - "dev": true - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "node_modules/@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/leaflet": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.5.tgz", - "integrity": "sha512-+Myo00Yb5OuvUyrH+vUwn9DRgOaBJsF/etIMdMcNhWGBMo58Mo1cxLInvCd0ZpvItju/AeDYFB/Od2pLiHB3VA==", - "dev": true, - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/linkify-it": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.0.tgz", - "integrity": "sha512-x9OaQQTb1N2hPZ/LWJsqushexDvz7NgzuZxiRmZio44WPuolTZNHDBCrOxCzRVOMwamJRO2dWax5NbygOf1OTQ==", - "dev": true - }, - "node_modules/@types/markdown-it": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.0.1.tgz", - "integrity": "sha512-mHfT8j/XkPb1uLEfs0/C3se6nd+webC2kcqcy8tgcVr0GDEONv/xaQzAN+aQvkxQXk/jC0Q6mPS+0xhFwRF35g==", - "dev": true, - "dependencies": { - "@types/highlight.js": "^9.7.0", - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "node_modules/@types/mdast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz", - "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==", - "dev": true, - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", - "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.1.tgz", - "integrity": "sha512-HnYlg/BRF8uC1FyKRFZwRaCPTPYKa+6I8QiUZFLredaGOou481cgFS4wKRFyKvQtX8xudqkSdBczJHIYSQYKrQ==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "node_modules/@types/orderedmap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz", - "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "node_modules/@types/prosemirror-markdown": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@types/prosemirror-markdown/-/prosemirror-markdown-1.5.1.tgz", - "integrity": "sha512-AqHCy80J9HUF+9FHveOB9fbKZwOf+1Ds2Vm1pPN6bfZ/Y6vdgXDry/hoz74+K7fQZZ8+f1J4x16llFj3PAohVg==", - "dev": true, - "dependencies": { - "@types/markdown-it": "*", - "@types/prosemirror-model": "*" - } - }, - "node_modules/@types/prosemirror-model": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.11.2.tgz", - "integrity": "sha512-mohs15V+gxj10QWJGVooErzSE9ryTo1Wy92lULiQ0BSN5Po9K4vngPzfKmLft0+gAPbEghovTX+I2zQW3bZo1w==", - "dev": true, - "dependencies": { - "@types/orderedmap": "*" - } - }, - "node_modules/@types/prosemirror-state": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.2.6.tgz", - "integrity": "sha512-tJo0wC+/cQvbrPDVx01Fnng9Fs41bAMVxgJY1KLOyIsUPN0otUN1KdoQurLMmHNHTvIna9ZXxjZD//xJKLYfJw==", - "dev": true, - "dependencies": { - "@types/prosemirror-model": "*", - "@types/prosemirror-transform": "*", - "@types/prosemirror-view": "*" - } - }, - "node_modules/@types/prosemirror-transform": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/prosemirror-transform/-/prosemirror-transform-1.1.2.tgz", - "integrity": "sha512-Ozyvs5Dquc49gaFysmC4gNhv6E65r569HSzw4RXdZgIljZ5Y9K4kHFlDvsWBBDH19+1178X9LMmM9J620O6Bug==", - "dev": true, - "dependencies": { - "@types/prosemirror-model": "*" - } - }, - "node_modules/@types/prosemirror-view": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/prosemirror-view/-/prosemirror-view-1.17.1.tgz", - "integrity": "sha512-PNiGGc6BffxHQzMR09UUilsBR8xFPDsKiPIXb4K/g56voPIvqq1pqySnWFfSR50Vo4ZL0tss3VBLWiiiKzVahQ==", - "dev": true, - "dependencies": { - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-transform": "*" - } - }, - "node_modules/@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", - "dev": true - }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "node_modules/@types/trusted-types": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz", - "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==" - }, - "node_modules/@types/unist": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", - "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", - "integrity": "sha512-CRQNQ0mC2Pa7VLwKFbrGVTArfdVDdefS+gTw0oC98vSI98IX5A8EVH4BzJ2FOB0YlCmm8Im36Elad/Jgtvveaw==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.19.0", - "@typescript-eslint/scope-manager": "4.19.0", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.19.0.tgz", - "integrity": "sha512-9/23F1nnyzbHKuoTqFN1iXwN3bvOm/PRIXSBR3qFAYotK/0LveEOHr5JT1WZSzcD6BESl8kPOG3OoDRKO84bHA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.19.0.tgz", - "integrity": "sha512-/uabZjo2ZZhm66rdAu21HA8nQebl3lAIDcybUoOxoI7VbZBYavLIwtOOmykKCJy+Xq6Vw6ugkiwn8Js7D6wieA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "debug": "^4.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.19.0.tgz", - "integrity": "sha512-GGy4Ba/hLXwJXygkXqMzduqOMc+Na6LrJTZXJWVhRrSuZeXmu8TAnniQVKgj8uTRKe4igO2ysYzH+Np879G75g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.19.0.tgz", - "integrity": "sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz", - "integrity": "sha512-3xqArJ/A62smaQYRv2ZFyTA+XxGGWmlDYrsfZG68zJeNbeqRScnhf81rUVa6QG4UgzHnXw5VnMT5cg75dQGDkA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.19.0.tgz", - "integrity": "sha512-aGPS6kz//j7XLSlgpzU2SeTqHPsmRYxFztj2vPuMMFJXZudpRSehE3WCV+BaxwZFvfAqMoSd86TEuM0PQ59E/A==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.19.0", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - } - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "adler32": "bin/adler32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "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==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/align-text/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/align-text/node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.0.tgz", - "integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/argv-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", - "dev": true - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "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-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=", - "dependencies": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" - } - }, - "node_modules/ast-transform/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=", - "engines": { - "node": ">= 0.6" - } - }, - "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/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.6.tgz", - "integrity": "sha512-8lChSmdU6dCNMCQopIf4Pe5kipkAGj/fvTMslCsih0uHpOrXOPUEVOmYMMqmw3cekQkSD7EhIeuYl5y0BLdKqg==", - "dev": true, - "peer": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-lite": "^1.0.30001230", - "colorette": "^1.2.2", - "fraction.js": "^4.1.1", - "normalize-range": "^0.1.2", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dependencies": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "node_modules/babel-runtime/node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true - }, - "node_modules/babel-runtime/node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "node_modules/bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "node_modules/before-after-hook": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/brfs": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", - "integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==", - "dependencies": { - "quote-stream": "^1.0.1", - "resolve": "^1.1.5", - "static-module": "^3.0.2", - "through2": "^2.0.0" - }, - "bin": { - "brfs": "bin/cmd.js" - } - }, - "node_modules/brfs/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/brotli": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.2.tgz", - "integrity": "sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y=", - "dependencies": { - "base64-js": "^1.1.2" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" - }, - "node_modules/browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dependencies": { - "resolve": "1.1.7" - } - }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - }, - "node_modules/browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=", - "dependencies": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" - } - }, - "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "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" - } - }, - "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.30001242", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", - "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", - "dev": true, - "dependencies": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - }, - "bin": { - "cdl": "bin/cdl.js" - } - }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cfb": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.1.tgz", - "integrity": "sha512-wT2ScPAFGSVy7CY+aauMezZBnNrfnaLSrxHUHdea+Td/86vrk6ZquggV+ssBR88zNs0OnBkL2+lf9q0K+zVGzQ==", - "dependencies": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0", - "printj": "~1.3.0" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/cfb/node_modules/adler-32": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.0.tgz", - "integrity": "sha512-f5nltvjl+PRUh6YNfUstRaXwJxtfnKEWhAWWlmKvh+Y3J2+98a0KKVYDEhz6NdKGqswLhjNGznxfSsZGOvOd9g==", - "dependencies": { - "printj": "~1.2.2" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/cfb/node_modules/adler-32/node_modules/printj": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.2.3.tgz", - "integrity": "sha512-sanczS6xOJOg7IKDvi4sGOUOe7c1tsEzjwlLFH/zgwx/uyImVM9/rgBkc8AfiQa/Vg54nRd8mkm9yI7WV/O+WA==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/cfb/node_modules/printj": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.0.tgz", - "integrity": "sha512-017o8YIaz8gLhaNxRB9eBv2mWXI2CtzhPJALnQTP+OPpuUfP0RMWqr/mHCzqVeu1AQxfzSfAtAq66vKB8y7Lzg==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "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/chalk/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/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/chalk/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/chalk/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/chalk/node_modules/supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true - }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "dependencies": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "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" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/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/chokidar/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/ci-info": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.1.1.tgz", - "integrity": "sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==", - "dev": true - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", - "dependencies": { - "exit": "0.1.2", - "glob": "^7.1.1" - }, - "engines": { - "node": ">=0.2.5" - } - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/cli-table3/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/cli-table3/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/cli-table3/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/cli-table3/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/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/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/cli-truncate/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" - } - }, - "node_modules/cli-truncate/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/cli-truncate/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/cli-truncate/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/cli-truncate/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/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/cliui/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/cliui/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-regexp": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", - "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", - "dev": true, - "dependencies": { - "is-regexp": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-regexp/node_modules/is-regexp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", - "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/coa/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/codepage": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", - "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", - "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.1", - "color-string": "^1.5.4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dev": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "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==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/commitizen": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz", - "integrity": "sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==", - "dev": true, - "dependencies": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", - "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", - "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", - "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" - }, - "bin": { - "commitizen": "bin/commitizen", - "cz": "bin/git-cz", - "git-cz": "bin/git-cz" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/commitizen/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/commitizen/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/commitizen/node_modules/cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" - } - }, - "node_modules/commitizen/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/commitizen/node_modules/find-node-modules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.2.tgz", - "integrity": "sha512-x+3P4mbtRPlSiVE1Qco0Z4YLU8WFiFcuWTf3m75OV9Uzcfs2Bg+O9N+r/K0AnmINBW06KpfqKwYJbFlFq4qNug==", - "dev": true, - "dependencies": { - "findup-sync": "^4.0.0", - "merge": "^2.1.0" - } - }, - "node_modules/commitizen/node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/commitizen/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/commitizen/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/commitizen/node_modules/merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, - "node_modules/commitizen/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/commitizen/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/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dependencies": { - "date-now": "^0.1.4" - } - }, - "node_modules/contour_plot": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", - "integrity": "sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=" - }, - "node_modules/conventional-changelog-angular": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", - "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", - "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", - "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", - "dev": true, - "dependencies": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.6", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - }, - "bin": { - "conventional-changelog-writer": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", - "dev": true - }, - "node_modules/conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", - "dev": true, - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-commits-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", - "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", - "dev": true, - "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0", - "trim-off-newlines": "^1.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cp-file": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", - "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "nested-error-stacks": "^2.0.0", - "p-event": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", - "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", - "dev": true, - "dependencies": { - "arrify": "^2.0.1", - "cp-file": "^7.0.0", - "globby": "^9.2.0", - "has-glob": "^1.0.0", - "junk": "^3.1.0", - "nested-error-stacks": "^2.1.0", - "p-all": "^2.1.0", - "p-filter": "^2.1.0", - "p-map": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy-cli": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-3.1.1.tgz", - "integrity": "sha512-HCpNdBkQy3rw+uARLuIf0YurqsMXYzBa9ihhSAuxYJcNIrqrSq3BstPfr0cQN38AdMrQiO9Dp4hYy7GtGJsLPg==", - "dev": true, - "dependencies": { - "cpy": "^8.0.0", - "meow": "^6.1.1" - }, - "bin": { - "cpy": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy-cli/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/cpy-cli/node_modules/meow": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", - "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "^4.0.2", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy-cli/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/cpy-cli/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/cpy-cli/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/cpy-cli/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cpy/node_modules/@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cpy/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cpy/node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy/node_modules/dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, - "dependencies": { - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cpy/node_modules/fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, - "dependencies": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/cpy/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/cpy/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cpy/node_modules/globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cpy/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/cpy/node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cpy/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cpy/node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cpy/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cpy/node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/crc-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", - "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crelt": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.4.tgz", - "integrity": "sha512-l1cwMUOssGLEj5zgbut4lxJq95ZabOXVZnDybNqQRUtXh1lvUK7e7kJNm8SfvTQzYpE3AVJhIVUJKf382lMA7A==" - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/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/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/css-blank-pseudo": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", - "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", - "dev": true, - "dependencies": { - "postcss": "^7.0.5" - }, - "bin": { - "css-blank-pseudo": "cli.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/css-blank-pseudo/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-blank-pseudo/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-blank-pseudo/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/css-blank-pseudo/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/css-blank-pseudo/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "engines": { - "node": ">4" - } - }, - "node_modules/css-declaration-sorter/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-declaration-sorter/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/css-declaration-sorter/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/css-declaration-sorter/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/css-has-pseudo": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", - "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^5.0.0-rc.4" - }, - "bin": { - "css-has-pseudo": "cli.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/css-has-pseudo/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-has-pseudo/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-has-pseudo/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-has-pseudo/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-has-pseudo/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/css-has-pseudo/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/css-prefers-color-scheme": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", - "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.5" - }, - "bin": { - "css-prefers-color-scheme": "cli.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/css-prefers-color-scheme/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-prefers-color-scheme/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/css-prefers-color-scheme/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/css-prefers-color-scheme/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/css-prefers-color-scheme/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/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/css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==", - "dev": true - }, - "node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssdb": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", - "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==", - "dev": true - }, - "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": "4.1.11", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", - "dev": true, - "dependencies": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-preset-default/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano-preset-default/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano-preset-default/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cssnano-preset-default/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/cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-raw-cache/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano-util-raw-cache/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano-util-raw-cache/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cssnano-util-raw-cache/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/cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano/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/cssnano/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/csso/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/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "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==" - }, - "node_modules/cz-conventional-changelog": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", - "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" - } - }, - "node_modules/cz-conventional-changelog/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "node_modules/d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" - }, - "node_modules/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "node_modules/d3-force": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-2.1.1.tgz", - "integrity": "sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==", - "dependencies": { - "d3-dispatch": "1 - 2", - "d3-quadtree": "1 - 2", - "d3-timer": "1 - 2" - } - }, - "node_modules/d3-geo": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-2.0.1.tgz", - "integrity": "sha512-M6yzGbFRfxzNrVhxDJXzJqSLQ90q1cCyb3EWFZ1LF4eWOBYxFypw7I/NFVBNXKNqxv1bqLathhYvdJ6DC+th3A==", - "dependencies": { - "d3-array": ">=2.5" - } - }, - "node_modules/d3-geo-projection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-3.0.0.tgz", - "integrity": "sha512-1JE+filVbkEX2bT25dJdQ05iA4QHvUwev6o0nIQHOSrNlHCAKfVss/U10vEM3pA4j5v7uQoFdQ4KLbx9BlEbWA==", - "dependencies": { - "commander": "2", - "d3-array": "1 - 2", - "d3-geo": "1.12.0 - 2", - "resolve": "^1.1.10" - }, - "bin": { - "geo2svg": "bin/geo2svg", - "geograticule": "bin/geograticule", - "geoproject": "bin/geoproject", - "geoquantize": "bin/geoquantize", - "geostitch": "bin/geostitch" - } - }, - "node_modules/d3-geo-projection/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==" - }, - "node_modules/d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/d3-quadtree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-2.0.0.tgz", - "integrity": "sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==" - }, - "node_modules/d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" - }, - "node_modules/d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" - }, - "node_modules/d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "node_modules/d3-transition/node_modules/d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "node_modules/d3-transition/node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dependencies": { - "ms": "2.1.2" - }, - "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": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "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.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" - }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "dependencies": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/dfa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" - }, - "node_modules/didyoumean": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz", - "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=", - "dev": true - }, - "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/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "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": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" - }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "dependencies": { - "minimatch": "^3.0.4" - }, - "bin": { - "ignored": "bin/ignored" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.766", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz", - "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w==", - "dev": true - }, - "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/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "node_modules/env-ci": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.4.1.tgz", - "integrity": "sha512-xyuCtyFZLpnW5aH0JstETKTSMwHHQX4m42juzEZzvbUCJX7RiPVlhASKM0f/cJ4vvI/+txMkZ7F5To6dCdPYhg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "fromentries": "^1.3.2", - "java-properties": "^1.0.0" - }, - "engines": { - "node": ">=10.17" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-ex/node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set/node_modules/es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/esbuild": { - "version": "0.12.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.12.tgz", - "integrity": "sha512-fdB/8HRg9u95Zi4/qV+osrfzpvLzubFKUr8SkZf/kUKImLiX61Y7qBzV14FCKphFk7YoXWY85nbPGkI6pq+Zeg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=", - "dependencies": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "optionalDependencies": { - "source-map": "~0.1.30" - } - }, - "node_modules/escodegen/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/escodegen/node_modules/esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "optional": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz", - "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.21", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.4", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", - "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", - "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/eslint/node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/eslint/node_modules/@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/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/eslint/node_modules/globals": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", - "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint/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/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/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" - } - }, - "node_modules/eslint/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" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "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/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-is-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/estree-is-function/-/estree-is-function-1.0.0.tgz", - "integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "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/execa/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/execa/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/execa/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/execall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", - "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", - "dev": true, - "dependencies": { - "clone-regexp": "^2.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/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/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.5.0.tgz", - "integrity": "sha512-+ONcYoWj/SoQwUofMr94aGu05Ou4FepKi7N7b+O8T4jVfyIsZQV1/xeS8jpaBzF0csAk0KLXoHCxU7cKYZjo1Q==", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", - "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", - "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.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/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/fast-glob/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/fast-glob/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/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": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz", - "integrity": "sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A==" - }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "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/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "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/find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "dependencies": { - "semver-regex": "^3.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatpickr": { - "version": "4.6.9", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", - "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==" - }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "node_modules/flatten": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", - "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", - "dev": true - }, - "node_modules/fmin": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", - "integrity": "sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=", - "dependencies": { - "contour_plot": "^0.0.1", - "json2module": "^0.0.3", - "rollup": "^0.25.8", - "tape": "^4.5.1", - "uglify-js": "^2.6.2" - } - }, - "node_modules/fmin/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/rollup": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", - "integrity": "sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=", - "dependencies": { - "chalk": "^1.1.1", - "minimist": "^1.2.0", - "source-map-support": "^0.3.2" - }, - "bin": { - "rollup": "bin/rollup" - } - }, - "node_modules/fmin/node_modules/source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fmin/node_modules/source-map-support": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", - "integrity": "sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=", - "dependencies": { - "source-map": "0.1.32" - } - }, - "node_modules/fmin/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fontkit": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.8.1.tgz", - "integrity": "sha512-BsNCjDoYRxmNWFdAuK1y9bQt+igIxGtTC9u/jSFjR9MKhmI00rP1fwSvERt+5ddE82544l0XH5mzXozQVUy2Tw==", - "dependencies": { - "babel-runtime": "^6.26.0", - "brfs": "^2.0.0", - "brotli": "^1.2.0", - "browserify-optional": "^1.0.1", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "^1.2.0", - "restructure": "^0.5.3", - "tiny-inflate": "^1.0.2", - "unicode-properties": "^1.2.2", - "unicode-trie": "^0.3.0" - } - }, - "node_modules/fontkit/node_modules/unicode-trie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", - "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/fraction.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz", - "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==", - "dev": true, - "peer": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "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/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", - "engines": { - "node": ">=6" - } - }, - "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-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" - }, - "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.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "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" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/git-log-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", - "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", - "dev": true, - "dependencies": { - "argv-formatter": "~1.0.0", - "spawn-error-forwarder": "~1.0.0", - "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "~0.6.6" - } - }, - "node_modules/git-log-parser/node_modules/split2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", - "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", - "dev": true, - "dependencies": { - "through2": "~2.0.0" - } - }, - "node_modules/git-log-parser/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/git-raw-commits": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", - "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", - "dev": true, - "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "git-raw-commits": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "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/glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "dependencies": { - "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", - "dev": true - }, - "node_modules/gonzales-pe": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", - "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "gonzales": "bin/gonzales.js" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/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/handlebars/node_modules/uglify-js": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", - "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/handlebars/node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "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": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", - "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=", - "dev": true, - "dependencies": { - "is-glob": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-glob/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true - }, - "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/hook-std": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", - "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "node_modules/hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dev": true, - "dependencies": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "node_modules/htmlparser2/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/http2-wrapper/node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/husky": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", - "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", - "dev": true, - "bin": { - "husky": "lib/bin.js" - } - }, - "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==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", - "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", - "dev": true, - "dependencies": { - "import-from": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-from/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/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "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/indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "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==" - }, - "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/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "node_modules/is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "dependencies": { - "call-bind": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==" - }, - "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.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", - "dependencies": { - "call-bind": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==" - }, - "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.1.1" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "dependencies": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "node_modules/is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "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": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/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==" - }, - "node_modules/is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dependencies": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "node_modules/is-ssh": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", - "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", - "dev": true, - "dependencies": { - "protocols": "^1.1.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, - "dependencies": { - "text-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "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" - } - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", - "dev": true, - "dependencies": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" - }, - "engines": { - "node": ">=10.13" - } - }, - "node_modules/java-properties": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsdom/node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/jsdom/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/jsdom/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/jsdom/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/jsdom/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/jsdom/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==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsdom/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jshint": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.1.tgz", - "integrity": "sha512-vymzfR3OysF5P774x6zYv0bD4EpH6NWRxpq54wO9mA9RuY49yb1teKSICkLx2Ryx+mfzlVVNNbTBtsRtg78t7g==", - "dependencies": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.21", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - }, - "bin": { - "jshint": "bin/jshint" - } - }, - "node_modules/jshint/node_modules/domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/jshint/node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/jshint/node_modules/entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" - }, - "node_modules/jshint/node_modules/htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "dependencies": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - } - }, - "node_modules/jshint/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "node_modules/jshint/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/jshint/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "node_modules/jshint/node_modules/strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "bin": { - "strip-json-comments": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "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-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.0.tgz", - "integrity": "sha512-o3aP+RsWDJZayj1SbHNQAI8x0v3T3SKiGoZlNYfbUP1S3omJQ6i9CnqADqkSPaOAxwua4/1YWx5CM7oiChJt2Q==", - "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json2module": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", - "integrity": "sha1-APtfSpt638PwZHwpyxe80Zeb6bI=", - "dependencies": { - "rw": "^1.3.2" - }, - "bin": { - "json2module": "bin/json2module" - } - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/junk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/keyv": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz", - "integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "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/known-css-properties": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.21.0.tgz", - "integrity": "sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw==", - "dev": true - }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/leaflet": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", - "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" - }, - "node_modules/leaflet.markercluster": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.1.tgz", - "integrity": "sha512-dRGndfMZibkWMBD7g8h+lJW0R0keTx1GGMErre7uhqnKiYBoMxR2VPX6Sy8oGNzg+FA7FKtTuO1hGh5HtV9s2g==", - "dependencies": { - "jshint": "^2.13.1", - "npm-ci": "0.0.2" - }, - "peerDependencies": { - "leaflet": "^1.3.1" - } - }, - "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/lilconfig": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz", - "integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/linebreak": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.0.2.tgz", - "integrity": "sha512-bJwSRsJeAmaZYnkcwl5sCQNfSDAhBuXxb6L27tb+qkBRtUQSSTUa5bcgCPD6hFEkRNlpWHfK7nFMmcANU7ZP1w==", - "dependencies": { - "base64-js": "0.0.8", - "brfs": "^2.0.2", - "unicode-trie": "^1.0.0" - } - }, - "node_modules/linebreak/node_modules/base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/linebreak/node_modules/unicode-trie": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-1.0.0.tgz", - "integrity": "sha512-v5raLKsobbFbWLMoX9+bChts/VhPPj3XpkNr/HbqkirXR1DPk8eo9IYKyvk0MQZFkaoRsFj2Rmaqgi2rfAZYtA==", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/lint-staged": { - "version": "10.5.4", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz", - "integrity": "sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "cli-truncate": "^2.1.0", - "commander": "^6.2.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.2.0", - "dedent": "^0.7.0", - "enquirer": "^2.3.6", - "execa": "^4.1.0", - "listr2": "^3.2.2", - "log-symbols": "^4.0.0", - "micromatch": "^4.0.2", - "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "^3.3.0" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - } - }, - "node_modules/lint-staged/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lint-staged/node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "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/lint-staged/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lint-staged/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lint-staged/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lint-staged/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/lint-staged/node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lint-staged/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" - } - }, - "node_modules/lint-staged/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" - } - }, - "node_modules/lint-staged/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/lint-staged/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/listr2": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.4.3.tgz", - "integrity": "sha512-wZmkzNiuinOfwrGqAwTCcPw6aKQGTAMGXwG5xeU1WpDjJNeBA35jGBeWxR3OF+R6Yl5Y3dRG+3vE8t6PDcSNHA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rxjs": "^6.6.6", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/listr2/node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/listr2/node_modules/rxjs": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", - "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/lit": { - "version": "2.0.0-rc.2", - "resolved": "https://registry.npmjs.org/lit/-/lit-2.0.0-rc.2.tgz", - "integrity": "sha512-BOCuoJR04WaTV8UqTKk09cNcQA10Aq2LCcBOiHuF7TzWH5RNDsbCBP5QM9sLBSotGTXbDug/gFO08jq6TbyEtw==", - "dependencies": { - "@lit/reactive-element": "^1.0.0-rc.2", - "lit-element": "^3.0.0-rc.2", - "lit-html": "^2.0.0-rc.3" - } - }, - "node_modules/lit-element": { - "version": "3.0.0-rc.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0-rc.2.tgz", - "integrity": "sha512-2Z7DabJ3b5K+p5073vFjMODoaWqy5PIaI4y6ADKm+fCGc8OnX9fU9dMoUEBZjFpd/bEFR9PBp050tUtBnT9XTQ==", - "dependencies": { - "@lit/reactive-element": "^1.0.0-rc.2", - "lit-html": "^2.0.0-rc.3" - } - }, - "node_modules/lit-html": { - "version": "2.0.0-rc.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0-rc.3.tgz", - "integrity": "sha512-Y6P8LlAyQuqvzq6l/Nc4z5/P5M/rVLYKQIRxcNwSuGajK0g4kbcBFQqZmgvqKG+ak+dHZjfm2HUw9TF5N/pkCw==", - "dependencies": { - "@types/trusted-types": "^1.0.1" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", - "dev": true - }, - "node_modules/lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU=", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", - "dev": true - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "dev": true - }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "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.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", - "dev": true - }, - "node_modules/lodash.topath": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", - "integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "node_modules/lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", - "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" - } - }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-update/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" - } - }, - "node_modules/log-update/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/log-update/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" - } - }, - "node_modules/log-update/node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/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/log-update/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/log-update/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/log-update/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" - } - }, - "node_modules/log-update/node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/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" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/longest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha1-eB4YMpaqlPbU2RbcM10NF676I/g=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/longest-streak": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", - "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", - "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/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/magic-string": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz", - "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", - "dependencies": { - "sourcemap-codec": "^1.4.1" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-obj": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.0.tgz", - "integrity": "sha512-NAq0fCmZYGz9UFEQyndp7sisrow4GroyGeKluyKC/chuITZsPyOyC1UJZPJlVFImhXdROIP5xqouRLThT3BbpQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" - }, - "node_modules/marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", - "dev": true, - "bin": { - "marked": "bin/marked" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/marked-terminal": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", - "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.1", - "cardinal": "^2.1.1", - "chalk": "^4.1.0", - "cli-table3": "^0.6.0", - "node-emoji": "^1.10.0", - "supports-hyperlinks": "^2.1.0" - }, - "peerDependencies": { - "marked": "^1.0.0 || ^2.0.0" - } - }, - "node_modules/marked-terminal/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/marked-terminal/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/matched": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/matched/-/matched-5.0.1.tgz", - "integrity": "sha512-E1fhSTPRyhAlNaNvGXAgZQlq1hL0bgYMTk/6bktVlIhzUnX/SZs7296ACdVeNJE8xFNGSuvd9IpI7vSnmcqLvw==", - "dependencies": { - "glob": "^7.1.6", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "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 - }, - "node_modules/mdast-util-from-markdown": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", - "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", - "dev": true, - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-string": "^2.0.0", - "micromark": "~2.11.0", - "parse-entities": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", - "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.0", - "longest-streak": "^2.0.0", - "mdast-util-to-string": "^2.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.0.0", - "zwitch": "^1.0.0" - } - }, - "node_modules/mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", - "dev": true - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "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" - } - }, - "node_modules/merge-source-map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", - "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", - "dependencies": { - "source-map": "^0.5.6" - } - }, - "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/micromark": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", - "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", - "dev": true, - "dependencies": { - "debug": "^4.0.0", - "parse-entities": "^2.0.0" - } - }, - "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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.45.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", - "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.28", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", - "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", - "dependencies": { - "mime-db": "1.45.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/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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-svg-data-uri": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.2.3.tgz", - "integrity": "sha512-zd6KCAyXgmq6FV1mR10oKXYtvmA9vRoB6xPSTUJTbFApCtkefDnYueVR1gkof3KcdLZo1Y8mjF2DFmQMIxsHNQ==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "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/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/modern-normalize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz", - "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "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/nerf-dart": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", - "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", - "dev": true - }, - "node_modules/nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/node-emoji": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", - "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", - "dev": true, - "dependencies": { - "lodash.toarray": "^4.4.0" - } - }, - "node_modules/node-fetch": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", - "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "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/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-selector": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz", - "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", - "dev": true - }, - "node_modules/normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.24.2.tgz", - "integrity": "sha512-120p116CE8VMMZ+hk8IAb1inCPk4Dj3VZw29/n2g6UI77urJKVYb7FZUDW8hY+EBnfsjI/2yrobBgFyzo7YpVQ==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/ci-detect", - "@npmcli/config", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/run-script", - "abbrev", - "ansicolors", - "ansistyles", - "archy", - "cacache", - "chalk", - "chownr", - "cli-columns", - "cli-table3", - "columnify", - "fastest-levenshtein", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmhook", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minipass", - "minipass-pipeline", - "mkdirp", - "mkdirp-infer-owner", - "ms", - "node-gyp", - "nopt", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "npmlog", - "opener", - "pacote", - "parse-conflict-json", - "qrcode-terminal", - "read", - "read-package-json", - "read-package-json-fast", - "readdir-scoped-modules", - "rimraf", - "semver", - "ssri", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which", - "write-file-atomic" - ], - "dev": true, - "dependencies": { - "@isaacs/string-locale-compare": "*", - "@npmcli/arborist": "*", - "@npmcli/ci-detect": "*", - "@npmcli/config": "*", - "@npmcli/map-workspaces": "*", - "@npmcli/package-json": "*", - "@npmcli/run-script": "*", - "abbrev": "*", - "ansicolors": "*", - "ansistyles": "*", - "archy": "*", - "cacache": "*", - "chalk": "*", - "chownr": "*", - "cli-columns": "*", - "cli-table3": "*", - "columnify": "*", - "fastest-levenshtein": "*", - "glob": "*", - "graceful-fs": "*", - "hosted-git-info": "*", - "ini": "*", - "init-package-json": "*", - "is-cidr": "*", - "json-parse-even-better-errors": "*", - "libnpmaccess": "*", - "libnpmdiff": "*", - "libnpmexec": "*", - "libnpmfund": "*", - "libnpmhook": "*", - "libnpmorg": "*", - "libnpmpack": "*", - "libnpmpublish": "*", - "libnpmsearch": "*", - "libnpmteam": "*", - "libnpmversion": "*", - "make-fetch-happen": "*", - "minipass": "*", - "minipass-pipeline": "*", - "mkdirp": "*", - "mkdirp-infer-owner": "*", - "ms": "*", - "node-gyp": "*", - "nopt": "*", - "npm-audit-report": "*", - "npm-install-checks": "*", - "npm-package-arg": "*", - "npm-pick-manifest": "*", - "npm-profile": "*", - "npm-registry-fetch": "*", - "npm-user-validate": "*", - "npmlog": "*", - "opener": "*", - "pacote": "*", - "parse-conflict-json": "*", - "qrcode-terminal": "*", - "read": "*", - "read-package-json": "*", - "read-package-json-fast": "*", - "readdir-scoped-modules": "*", - "rimraf": "*", - "semver": "*", - "ssri": "*", - "tar": "*", - "text-table": "*", - "tiny-relative-date": "*", - "treeverse": "*", - "validate-npm-package-name": "*", - "which": "*", - "write-file-atomic": "*" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-ci": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/npm-ci/-/npm-ci-0.0.2.tgz", - "integrity": "sha1-n2t2IMKFeAL7baJoEGnkCinjEHI=", - "deprecated": "Test package" - }, - "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/npm/node_modules/@gar/promisify": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "2.9.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^1.0.2", - "@npmcli/metavuln-calculator": "^1.1.0", - "@npmcli/move-file": "^1.1.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^1.0.1", - "@npmcli/package-json": "^1.0.1", - "@npmcli/run-script": "^1.8.2", - "bin-links": "^2.2.1", - "cacache": "^15.0.3", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.1.5", - "npm-pick-manifest": "^6.1.0", - "npm-registry-fetch": "^11.0.0", - "pacote": "^11.3.5", - "parse-conflict-json": "^1.1.1", - "proc-log": "^1.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "ssri": "^8.0.1", - "treeverse": "^1.0.4", - "walk-up-path": "^1.0.0" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/@npmcli/ci-detect": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "ini": "^2.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^5.0.0", - "semver": "^7.3.4", - "walk-up-path": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/@npmcli/disparity-colors": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "ansi-styles": "^4.3.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - } - }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "read-package-json-fast": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "cacache": "^15.0.5", - "pacote": "^11.1.11", - "semver": "^7.3.2" - } - }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.1" - } - }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "1.3.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "infer-owner": "^1.0.4" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "1.8.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" - } - }, - "node_modules/npm/node_modules/@tootallnate/once": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/agent-base": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/npm/node_modules/agentkeepalive": { - "version": "4.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/npm/node_modules/aggregate-error": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/ansicolors": { - "version": "0.3.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ansistyles": { - "version": "0.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/are-we-there-yet": { - "version": "1.1.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/asap": { - "version": "2.0.6", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/asn1": { - "version": "0.2.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/npm/node_modules/assert-plus": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/asynckit": { - "version": "0.4.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/aws-sign2": { - "version": "0.7.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/aws4": { - "version": "1.11.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/npm/node_modules/bin-links": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^4.0.1", - "mkdirp": "^1.0.3", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^2.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/builtins": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/cacache": { - "version": "15.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/caseless": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/npm/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^4.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "3.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^2.0.0", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/npm/node_modules/cli-table3/node_modules/ansi-regex": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-table3/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-table3/node_modules/string-width": { - "version": "4.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-table3/node_modules/strip-ansi": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "mkdirp-infer-owner": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/code-point-at": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/color-support": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/npm/node_modules/colors": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/npm/node_modules/columnify": { - "version": "1.5.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - } - }, - "node_modules/npm/node_modules/combined-stream": { - "version": "1.0.8", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/core-util-is": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/dashdash": { - "version": "1.14.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "4.3.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/debuglog": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/npm/node_modules/delayed-stream": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/depd": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/dezalgo": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/diff": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/npm/node_modules/ecc-jsbn": { - "version": "0.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/extend": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/extsprintf": { - "version": "1.3.0", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.12", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/forever-agent": { - "version": "0.6.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/gauge": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1 || ^2.0.0", - "strip-ansi": "^3.0.1 || ^4.0.0", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/getpass": { - "version": "0.1.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.8", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/har-schema": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/har-validator": { - "version": "5.1.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/has": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/npm/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/has-unicode": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "4.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/http-signature": { - "version": "1.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/humanize-ms": { - "version": "1.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^3.0.4" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/indent-string": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ini": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "2.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^8.1.5", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "^4.1.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ip": { - "version": "1.1.5", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "4.0.2", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^3.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.7.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/is-lambda": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/is-typedarray": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/isstream": { - "version": "0.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/jsbn": { - "version": "0.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/json-schema": { - "version": "0.2.3", - "dev": true, - "inBundle": true - }, - "node_modules/npm/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/json-stringify-safe": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/jsprim": { - "version": "1.4.1", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/npm/node_modules/just-diff": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/disparity-colors": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^3.0.4", - "npm-package-arg": "^8.1.4", - "pacote": "^11.3.4", - "tar": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^2.3.0", - "@npmcli/ci-detect": "^1.3.0", - "@npmcli/run-script": "^1.8.4", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^8.1.2", - "pacote": "^11.3.1", - "proc-log": "^1.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "walk-up-path": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^2.5.0" - } - }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "6.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/run-script": "^1.8.3", - "npm-package-arg": "^8.1.0", - "pacote": "^11.2.6" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "4.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "normalize-package-data": "^3.0.2", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0", - "semver": "^7.1.3", - "ssri": "^8.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "3.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "1.2.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^2.0.7", - "@npmcli/run-script": "^1.8.4", - "json-parse-even-better-errors": "^2.3.1", - "semver": "^7.3.5", - "stringify-package": "^1.0.1" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "9.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/mime-db": { - "version": "1.49.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/mime-types": { - "version": "2.1.32", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.49.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/minipass": { - "version": "3.1.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "1.4.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minizlib": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/mkdirp-infer-owner": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "0.0.8", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/negotiator": { - "version": "0.6.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "7.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/aproba": { - "version": "1.2.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { - "version": "2.7.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/npmlog": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/string-width": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "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/npm/node_modules/npm-audit-report": { - "version": "2.1.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "8.1.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "2.2.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "6.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "5.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^11.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "11.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/npmlog": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/number-is-nan": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/oauth-sign": { - "version": "0.9.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/once": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/opener": { - "version": "1.5.2", - "dev": true, - "inBundle": true, - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/npm/node_modules/p-map": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/pacote": { - "version": "11.3.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - }, - "bin": { - "pacote": "lib/bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "just-diff": "^3.0.1", - "just-diff-apply": "^3.0.0" - } - }, - "node_modules/npm/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/performance-now": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/proc-log": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-inflight": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "0.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "1" - } - }, - "node_modules/npm/node_modules/psl": { - "version": "1.8.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/punycode": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/qs": { - "version": "6.5.2", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/npm/node_modules/read": { - "version": "1.0.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/read-package-json": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/readable-stream": { - "version": "3.6.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/npm/node_modules/request": { - "version": "2.88.2", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/npm/node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.2.1", - "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" - } - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/semver": { - "version": "7.3.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/set-blocking": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.6.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip": "^1.1.5", - "smart-buffer": "^4.1.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "6.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.10", - "dev": true, - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/sshpk": { - "version": "1.16.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ssri": { - "version": "8.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/stringify-package": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "6.1.11", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/treeverse": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/tunnel-agent": { - "version": "0.6.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/tweetnacl": { - "version": "0.14.5", - "dev": true, - "inBundle": true, - "license": "Unlicense" - }, - "node_modules/npm/node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/npm/node_modules/unique-filename": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/npm/node_modules/unique-slug": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/npm/node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/uuid": { - "version": "3.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "builtins": "^1.0.3" - } - }, - "node_modules/npm/node_modules/verror": { - "version": "1.10.0", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/npm/node_modules/which": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/wide-align": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/npm/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/onetime/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "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.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/orderedmap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.1.tgz", - "integrity": "sha512-3Ux8um0zXbVacKUkcytc0u3HgC0b0bBLT+I60r2J/En72cI0nZffqrA7Xtf2Hqs27j1g82llR5Mhbd0Z1XW4AQ==" - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-all": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", - "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", - "dev": true, - "dependencies": { - "p-map": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-all/node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dev": true, - "dependencies": { - "p-timeout": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-filter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", - "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", - "dev": true, - "dependencies": { - "p-map": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-filter/node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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" - } - }, - "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-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/p-reduce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "dependencies": { - "p-finally": "^1.0.0" - }, - "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/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, - "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/parent-module/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/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-path": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz", - "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", - "dev": true, - "dependencies": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0", - "qs": "^6.9.4", - "query-string": "^6.13.8" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "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==" - }, - "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/pdfkit": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.12.3.tgz", - "integrity": "sha512-+qDLgm2yq6WOKcxTb43lDeo3EtMIDQs0CK1RNqhHC9iT6u0KOmgwAClkYh9xFw2ATbmUZzt4f7KMwDCOfPDluA==", - "dependencies": { - "crypto-js": "^4.0.0", - "fontkit": "^1.8.1", - "linebreak": "^1.0.2", - "png-js": "^1.0.0" - } - }, - "node_modules/pdfmake": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.2.tgz", - "integrity": "sha512-e1N+iIIf0LXTvfmf/RaxeqtOKX2qFrNxBbcWmMcg2BUsgcye1bLkdxR7PImmRs8OnqT7qd9XonltZgdTFw8qUA==", - "dependencies": { - "@foliojs-fork/linebreak": "^1.1.1", - "@foliojs-fork/pdfkit": "^0.12.3", - "iconv-lite": "^0.6.3", - "svg-to-pdfkit": "^0.1.8", - "xmldoc": "^1.1.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/pdfmake/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/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "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": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "dependencies": { - "semver-compare": "^1.0.0" - } - }, - "node_modules/png-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", - "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" - }, - "node_modules/polylabel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/polylabel/-/polylabel-1.1.0.tgz", - "integrity": "sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==", - "dependencies": { - "tinyqueue": "^2.0.3" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", - "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", - "dev": true, - "dependencies": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", - "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^6.0.2" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive/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/postcss-attribute-case-insensitive/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/postcss-calc/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-calc/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-calc/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-calc/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/postcss-color-functional-notation": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", - "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-functional-notation/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-functional-notation/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-functional-notation/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-functional-notation/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/postcss-color-functional-notation/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-color-gray": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", - "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", - "dev": true, - "dependencies": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-gray/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-gray/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-gray/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-gray/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/postcss-color-gray/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", - "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.14", - "postcss-values-parser": "^2.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-hex-alpha/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-hex-alpha/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-hex-alpha/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-hex-alpha/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/postcss-color-hex-alpha/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-color-mod-function": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", - "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", - "dev": true, - "dependencies": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-mod-function/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-mod-function/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-mod-function/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-mod-function/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/postcss-color-mod-function/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-color-rebeccapurple": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", - "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-rebeccapurple/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-rebeccapurple/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-rebeccapurple/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-rebeccapurple/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/postcss-color-rebeccapurple/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-colormin/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-colormin/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-colormin/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-colormin/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-colormin/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/postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-convert-values/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-convert-values/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-convert-values/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-convert-values/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/postcss-custom-media": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", - "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-media/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-media/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-media/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-media/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/postcss-custom-media/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-custom-properties": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", - "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.17", - "postcss-values-parser": "^2.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-properties/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-properties/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-properties/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-properties/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/postcss-custom-properties/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-custom-selectors": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", - "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-selectors/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/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/postcss-custom-selectors/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-dir-pseudo-class": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", - "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/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/postcss-dir-pseudo-class/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-comments/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-discard-comments/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-comments/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-discard-comments/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/postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-duplicates/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-discard-duplicates/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-duplicates/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-discard-duplicates/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/postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-empty/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-discard-empty/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-empty/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-discard-empty/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/postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-overridden/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-discard-overridden/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-overridden/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-discard-overridden/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/postcss-double-position-gradients": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", - "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-double-position-gradients/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-double-position-gradients/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-double-position-gradients/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-double-position-gradients/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/postcss-double-position-gradients/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-env-function": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", - "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-env-function/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-env-function/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-env-function/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-env-function/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/postcss-env-function/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-focus-visible": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", - "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-focus-visible/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-focus-visible/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-focus-visible/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-focus-visible/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/postcss-focus-visible/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-focus-within": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", - "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-focus-within/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-focus-within/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-focus-within/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-focus-within/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/postcss-focus-within/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-font-variant": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", - "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-font-variant/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-font-variant/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-font-variant/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-font-variant/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/postcss-font-variant/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-gap-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", - "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-gap-properties/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-gap-properties/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-gap-properties/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-gap-properties/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/postcss-gap-properties/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-html": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", - "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", - "dev": true, - "dependencies": { - "htmlparser2": "^3.10.0" - } - }, - "node_modules/postcss-image-set-function": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", - "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-image-set-function/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-image-set-function/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-image-set-function/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-image-set-function/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/postcss-image-set-function/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-import": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.0.tgz", - "integrity": "sha512-gFDDzXhqr9ELmnLHgCC3TbGfA6Dm/YMb/UN8/f7Uuq4fL7VTk2vOIj6hwINEwbokEmp123bLD7a5m+E+KIetRg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/postcss-initial": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz", - "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-initial/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-initial/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-initial/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-initial/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/postcss-initial/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-js": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", - "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1", - "postcss": "^8.1.6" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/postcss-lab-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", - "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", - "dev": true, - "dependencies": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-lab-function/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-lab-function/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-lab-function/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-lab-function/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/postcss-lab-function/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-less": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", - "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">=6.14.4" - } - }, - "node_modules/postcss-less/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-less/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-less/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-less/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/postcss-less/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", - "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", - "dev": true, - "dependencies": { - "import-cwd": "^3.0.0", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-logical": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", - "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-logical/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-logical/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-logical/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-logical/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/postcss-logical/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-media-minmax": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", - "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-media-minmax/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-media-minmax/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-media-minmax/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-media-minmax/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/postcss-media-minmax/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", - "dev": true - }, - "node_modules/postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, - "dependencies": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-longhand/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-merge-longhand/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-merge-longhand/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-merge-longhand/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/postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-rules/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-merge-rules/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-merge-rules/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-merge-rules/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/postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-font-values/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-minify-font-values/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-font-values/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-minify-font-values/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/postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-gradients/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-minify-gradients/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-gradients/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-minify-gradients/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/postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-params/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-minify-params/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-params/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-minify-params/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/postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-selectors/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-minify-selectors/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-minify-selectors/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-minify-selectors/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/postcss-nested": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.5.tgz", - "integrity": "sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/postcss-nesting": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", - "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-nesting/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-nesting/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-nesting/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-nesting/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/postcss-nesting/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-charset/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-charset/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-charset/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-charset/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/postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-display-values/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-display-values/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/postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-positions/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-positions/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-positions/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-positions/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/postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-repeat-style/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/postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, - "dependencies": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-string/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-string/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-string/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-string/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/postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-timing-functions/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/postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-unicode/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-unicode/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/postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, - "dependencies": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-url/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-url/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-url/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-url/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/postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-normalize-whitespace/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/postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-ordered-values/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-ordered-values/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-ordered-values/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-ordered-values/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/postcss-overflow-shorthand": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", - "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-overflow-shorthand/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-overflow-shorthand/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-overflow-shorthand/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-overflow-shorthand/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/postcss-overflow-shorthand/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-page-break": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", - "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-page-break/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-page-break/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-page-break/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-page-break/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/postcss-page-break/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-place": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", - "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-place/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-place/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-place/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-place/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/postcss-place/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-preset-env": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", - "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", - "dev": true, - "dependencies": { - "autoprefixer": "^9.6.1", - "browserslist": "^4.6.4", - "caniuse-lite": "^1.0.30000981", - "css-blank-pseudo": "^0.1.4", - "css-has-pseudo": "^0.10.0", - "css-prefers-color-scheme": "^3.1.1", - "cssdb": "^4.4.0", - "postcss": "^7.0.17", - "postcss-attribute-case-insensitive": "^4.0.1", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-gray": "^5.0.0", - "postcss-color-hex-alpha": "^5.0.3", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.8", - "postcss-custom-properties": "^8.0.11", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-double-position-gradients": "^1.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-preset-env/node_modules/autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", - "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", - "dev": true, - "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - }, - "node_modules/postcss-preset-env/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-preset-env/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-preset-env/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-preset-env/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/postcss-preset-env/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", - "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/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/postcss-pseudo-class-any-link/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-initial/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-reduce-initial/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-reduce-initial/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-reduce-initial/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/postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-reduce-transforms/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-reduce-transforms/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/postcss-replace-overflow-wrap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", - "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-replace-overflow-wrap/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/postcss-replace-overflow-wrap/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=", - "dev": true - }, - "node_modules/postcss-safe-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", - "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.26" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-safe-parser/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-safe-parser/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-safe-parser/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-safe-parser/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/postcss-safe-parser/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-sass": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz", - "integrity": "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==", - "dev": true, - "dependencies": { - "gonzales-pe": "^4.3.0", - "postcss": "^7.0.21" - } - }, - "node_modules/postcss-sass/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-sass/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-sass/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-sass/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/postcss-sass/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-scss": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz", - "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-scss/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-scss/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-scss/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/postcss-scss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-selector-matches": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", - "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-selector-matches/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-matches/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-matches/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-selector-matches/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/postcss-selector-matches/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-selector-not": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", - "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-selector-not/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-not/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-selector-not/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-selector-not/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/postcss-selector-not/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-svgo/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-svgo/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-svgo/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-svgo/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/postcss-svgo/node_modules/svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-syntax": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", - "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", - "dev": true - }, - "node_modules/postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-unique-selectors/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-unique-selectors/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-unique-selectors/node_modules/postcss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/postcss-unique-selectors/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/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "node_modules/postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "dev": true, - "dependencies": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=6.14.4" - } - }, - "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": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/prettier-plugin-organize-imports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-1.1.1.tgz", - "integrity": "sha512-rFA1lnek1FYkMGthm4xBKME41qUKItTovuo24bCGZu/Vu1n3gW71UPLAkIdwewwkZCe29gRVweSOPXvAdckFuw==", - "dev": true - }, - "node_modules/pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "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==" - }, - "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/prosemirror-commands": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.1.4.tgz", - "integrity": "sha512-kj4Qi+8h3EpJtZuuEDwZ9h2/QNGWDsIX/CzjmClxi9GhxWyBUMVUvIFk0mgdqHyX20lLeGmOpc0TLA5aPzgpWg==", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-dropcursor": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.3.2.tgz", - "integrity": "sha512-4c94OUGyobGnwcQI70OXyMhE/9T4aTgjU+CHxkd5c7D+jH/J0mKM/lk+jneFVKt7+E4/M0D9HzRPifu8U28Thw==", - "dependencies": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0", - "prosemirror-view": "^1.1.0" - } - }, - "node_modules/prosemirror-example-setup": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-example-setup/-/prosemirror-example-setup-1.1.2.tgz", - "integrity": "sha512-MTpIMyqk08jFnzxeRMCinCEMtVSTUtxKgQBGxfCbVe9C6zIOqp9qZZJz5Ojaad1GETySyuj8+OIHHvQsIaaaGQ==", - "dependencies": { - "prosemirror-commands": "^1.0.0", - "prosemirror-dropcursor": "^1.0.0", - "prosemirror-gapcursor": "^1.0.0", - "prosemirror-history": "^1.0.0", - "prosemirror-inputrules": "^1.0.0", - "prosemirror-keymap": "^1.0.0", - "prosemirror-menu": "^1.0.0", - "prosemirror-schema-list": "^1.0.0", - "prosemirror-state": "^1.0.0" - } - }, - "node_modules/prosemirror-gapcursor": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.1.5.tgz", - "integrity": "sha512-SjbUZq5pgsBDuV3hu8GqgIpZR5eZvGLM+gPQTqjVVYSMUCfKW3EGXTEYaLHEl1bGduwqNC95O3bZflgtAb4L6w==", - "dependencies": { - "prosemirror-keymap": "^1.0.0", - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-view": "^1.0.0" - } - }, - "node_modules/prosemirror-history": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.1.3.tgz", - "integrity": "sha512-zGDotijea+vnfnyyUGyiy1wfOQhf0B/b6zYcCouBV8yo6JmrE9X23M5q7Nf/nATywEZbgRLG70R4DmfSTC+gfg==", - "dependencies": { - "prosemirror-state": "^1.2.2", - "prosemirror-transform": "^1.0.0", - "rope-sequence": "^1.3.0" - } - }, - "node_modules/prosemirror-inputrules": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.1.2.tgz", - "integrity": "sha512-Ja5Z3BWestlHYGvtSGqyvxMeB8QEuBjlHM8YnKtLGUXMDp965qdDV4goV8lJb17kIWHk7e7JNj6Catuoa3302g==", - "dependencies": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-keymap": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.1.4.tgz", - "integrity": "sha512-Al8cVUOnDFL4gcI5IDlG6xbZ0aOD/i3B17VT+1JbHWDguCgt/lBHVTHUBcKvvbSg6+q/W4Nj1Fu6bwZSca3xjg==", - "dependencies": { - "prosemirror-state": "^1.0.0", - "w3c-keyname": "^2.2.0" - } - }, - "node_modules/prosemirror-markdown": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.5.1.tgz", - "integrity": "sha512-QvucPHx+gKOQW1SETKUysrful9VBjKqpCFmPotgLfVZ3BdQEGy/NEIFhaXXo3TcuW316MMnKfA90K7GE5I7z8A==", - "dependencies": { - "markdown-it": "^10.0.0", - "prosemirror-model": "^1.0.0" - } - }, - "node_modules/prosemirror-menu": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.1.4.tgz", - "integrity": "sha512-2ROsji/X9ciDnVSRvSTqFygI34GEdHfQSsK4zBKjPxSEroeiHHcdRMS1ofNIf2zM0Vpp5/YqfpxynElymQkqzg==", - "dependencies": { - "crelt": "^1.0.0", - "prosemirror-commands": "^1.0.0", - "prosemirror-history": "^1.0.0", - "prosemirror-state": "^1.0.0" - } - }, - "node_modules/prosemirror-model": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.11.0.tgz", - "integrity": "sha512-GqoAz/mIYjdv8gVYJ8mWFKpHoTxn/lXq4tXJ6bTVxs+rem2LzMYXrNVXfucGtfsgqsJlRIgng/ByG9j7Q8XDrg==", - "dependencies": { - "orderedmap": "^1.1.0" - } - }, - "node_modules/prosemirror-schema-list": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.1.2.tgz", - "integrity": "sha512-dgM9PwtM4twa5WsgSYMB+J8bwjnR43DAD3L9MsR9rKm/nZR5Y85xcjB7gusVMSsbQ2NomMZF03RE6No6mTnclQ==", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-state": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.3.4.tgz", - "integrity": "sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==", - "dependencies": { - "prosemirror-model": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "node_modules/prosemirror-transform": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.2.7.tgz", - "integrity": "sha512-/107Lo2zeDgXuJBxb8s/clNu0Z2W8Gv3MKmkuSS/68Mcr7LBaUnN/Hj2g+GUxEJ7MpExCzFs65GrsNo2K9rxUQ==", - "dependencies": { - "prosemirror-model": "^1.0.0" - } - }, - "node_modules/prosemirror-view": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.18.1.tgz", - "integrity": "sha512-TZd8byDRfdopLiokBY7T27msCSfWqqRxWs/LnBbdI030F+iI2kS+tO59/XFnpZxMLFKlJgOgGGhM9SzD1Nwdxw==", - "dependencies": { - "prosemirror-model": "^1.1.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0" - } - }, - "node_modules/protocols": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", - "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", - "dev": true - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/purgecss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.0.3.tgz", - "integrity": "sha512-PYOIn5ibRIP34PBU9zohUcCI09c7drPJJtTDAc0Q6QlRz2/CHQ8ywGLdE7ZhxU2VTqB7p5wkvj5Qcm05Rz3Jmw==", - "dev": true, - "dependencies": { - "commander": "^6.0.0", - "glob": "^7.0.0", - "postcss": "^8.2.1", - "postcss-selector-parser": "^6.0.2" - }, - "bin": { - "purgecss": "bin/purgecss.js" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/query-string": { - "version": "6.13.8", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.8.tgz", - "integrity": "sha512-jxJzQI2edQPE/NPUOusNjO/ZOGqr1o2OBa/3M00fU76FsLXDVbJDv/p7ng5OdQyorKrkRz1oqfwmbe5MAMePQg==", - "dev": true, - "dependencies": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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/quote-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", - "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", - "dependencies": { - "buffer-equal": "0.0.1", - "minimist": "^1.1.3", - "through2": "^2.0.0" - }, - "bin": { - "quote-stream": "bin/cmd.js" - } - }, - "node_modules/quote-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "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": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", - "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" - } - }, - "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/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" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "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": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "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/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/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/redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "dev": true, - "dependencies": { - "esprima": "~4.0.0" - } - }, - "node_modules/reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", - "dev": true, - "dependencies": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" - } - }, - "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "dependencies": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/regression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", - "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=" - }, - "node_modules/remark": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", - "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", - "dev": true, - "dependencies": { - "remark-parse": "^9.0.0", - "remark-stringify": "^9.0.0", - "unified": "^9.1.0" - } - }, - "node_modules/remark-parse": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", - "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", - "dev": true, - "dependencies": { - "mdast-util-from-markdown": "^0.8.0" - } - }, - "node_modules/remark-stringify": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz", - "integrity": "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==", - "dev": true, - "dependencies": { - "mdast-util-to-markdown": "^0.6.0" - } - }, - "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "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/resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "dependencies": { - "global-dirs": "^0.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "node_modules/responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - } - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/restructure": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-0.5.4.tgz", - "integrity": "sha1-9U591WNZD7NP1r9Vh2EJrsyyjeg=", - "dependencies": { - "browserify-optional": "^1.0.0" - } - }, - "node_modules/resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dependencies": { - "through": "~2.3.4" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "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.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "node_modules/rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "node_modules/rgbcolor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha1-1lBezbMEplldom+ktDMHMGd1lF0=", - "engines": { - "node": ">= 0.8.15" - } - }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rollup": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.42.4.tgz", - "integrity": "sha512-Zqv3EvNfcllBHyyEUM754npqsZw82VIjK34cDQMwrQ1d6aqxzeYu5yFb7smGkPU4C1Bj7HupIMeT6WU7uIdnMw==", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/rollup-plugin-multi-input": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-multi-input/-/rollup-plugin-multi-input-1.2.0.tgz", - "integrity": "sha512-jLmVLYpIB9sFk3JmzwKFryPqZYv1Dib/GzQEy708hfD/xauwgOyKWk7qhKMQp71mbGTuF59neUst/cnveIii+A==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.0.0-beta.55", - "core-js": "^3.1.3", - "fast-glob": "^3.0.0", - "lodash": "^4.17.11" - } - }, - "node_modules/rope-sequence": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.2.tgz", - "integrity": "sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg==" - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" - }, - "node_modules/rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", - "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "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==" - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "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/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/scope-analyzer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.1.tgz", - "integrity": "sha512-azEAihtQ9mEyZGhfgTJy3IbOWEzeOrYbg7NcYEshPKnKd+LZmC3TNd5dmDxbLBsTG/JVWmCp+vDJ03vJjeXMHg==", - "dependencies": { - "array-from": "^2.1.1", - "dash-ast": "^1.0.0", - "es6-map": "^0.1.5", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.1", - "estree-is-function": "^1.0.0", - "get-assigned-identifiers": "^1.1.0" - } - }, - "node_modules/semantic-release": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-18.0.0.tgz", - "integrity": "sha512-/Szyhq5DTZCYry/aZqpBbK/kqv10ydn6oiiaYOXtPgDbAIkqidZcQOm+mfYFJ0sBTUaOYCKMlcPMgJycP7jDYQ==", - "dev": true, - "dependencies": { - "@semantic-release/commit-analyzer": "^9.0.0", - "@semantic-release/error": "^3.0.0", - "@semantic-release/github": "^8.0.0", - "@semantic-release/npm": "^8.0.0", - "@semantic-release/release-notes-generator": "^10.0.0", - "aggregate-error": "^3.0.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.0.0", - "env-ci": "^5.0.0", - "execa": "^5.0.0", - "figures": "^3.0.0", - "find-versions": "^4.0.0", - "get-stream": "^6.0.0", - "git-log-parser": "^1.2.0", - "hook-std": "^2.0.0", - "hosted-git-info": "^4.0.0", - "lodash": "^4.17.21", - "marked": "^2.0.0", - "marked-terminal": "^4.1.1", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "p-reduce": "^2.0.0", - "read-pkg-up": "^7.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.3.2", - "semver-diff": "^3.1.1", - "signale": "^1.2.1", - "yargs": "^16.2.0" - }, - "bin": { - "semantic-release": "bin/semantic-release.js" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/semantic-release/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "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/semantic-release/node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semantic-release/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/semantic-release/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semantic-release/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/semantic-release/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/semantic-release/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/semantic-release/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/semantic-release/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/semantic-release/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semantic-release/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/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-regex": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz", - "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" - }, - "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/shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/signale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", - "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", - "dev": true, - "dependencies": { - "chalk": "^2.3.2", - "figures": "^2.0.0", - "pkg-conf": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/signale/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "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" - } - }, - "node_modules/slice-ansi/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" - } - }, - "node_modules/slice-ansi/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/slice-ansi/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/slice-ansi/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/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/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/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "node_modules/spawn-error-forwarder": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", - "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "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-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "node_modules/specificity": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz", - "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", - "dev": true, - "bin": { - "specificity": "bin/specificity" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/ssf": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", - "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "dependencies": { - "frac": "~1.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "node_modules/stackblur-canvas": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz", - "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==", - "engines": { - "node": ">=0.1.14" - } - }, - "node_modules/static-eval": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", - "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", - "dependencies": { - "escodegen": "^1.11.1" - } - }, - "node_modules/static-eval/node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/static-eval/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/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==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-eval/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-module": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/static-module/-/static-module-3.0.4.tgz", - "integrity": "sha512-gb0v0rrgpBkifXCa3yZXxqVmXDVE+ETXj6YlC/jt5VzOnGXR2C15+++eXuMDUYsePnbhf+lwW0pE1UXyOLtGCw==", - "dependencies": { - "acorn-node": "^1.3.0", - "concat-stream": "~1.6.0", - "convert-source-map": "^1.5.1", - "duplexer2": "~0.1.4", - "escodegen": "^1.11.1", - "has": "^1.0.1", - "magic-string": "0.25.1", - "merge-source-map": "1.0.4", - "object-inspect": "^1.6.0", - "readable-stream": "~2.3.3", - "scope-analyzer": "^2.0.1", - "shallow-copy": "~0.0.1", - "static-eval": "^2.0.5", - "through2": "~2.0.3" - } - }, - "node_modules/static-module/node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/static-module/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-module/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-module/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-module/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==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-module/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/static-module/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "dependencies": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "node_modules/strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", - "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stringify-object/node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=", - "dev": true - }, - "node_modules/stylehacks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.0.tgz", - "integrity": "sha1-ZLMjlRxKJOX8ey7AbBN78y0VXoo=", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^6.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/stylehacks/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stylehacks/node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/stylehacks/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stylehacks/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/stylelint": { - "version": "13.13.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.13.1.tgz", - "integrity": "sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ==", - "dev": true, - "dependencies": { - "@stylelint/postcss-css-in-js": "^0.37.2", - "@stylelint/postcss-markdown": "^0.36.2", - "autoprefixer": "^9.8.6", - "balanced-match": "^2.0.0", - "chalk": "^4.1.1", - "cosmiconfig": "^7.0.0", - "debug": "^4.3.1", - "execall": "^2.0.0", - "fast-glob": "^3.2.5", - "fastest-levenshtein": "^1.0.12", - "file-entry-cache": "^6.0.1", - "get-stdin": "^8.0.0", - "global-modules": "^2.0.0", - "globby": "^11.0.3", - "globjoin": "^0.1.4", - "html-tags": "^3.1.0", - "ignore": "^5.1.8", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "known-css-properties": "^0.21.0", - "lodash": "^4.17.21", - "log-symbols": "^4.1.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.4", - "normalize-selector": "^0.2.0", - "postcss": "^7.0.35", - "postcss-html": "^0.36.0", - "postcss-less": "^3.1.4", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^4.0.2", - "postcss-sass": "^0.4.4", - "postcss-scss": "^2.1.1", - "postcss-selector-parser": "^6.0.5", - "postcss-syntax": "^0.36.2", - "postcss-value-parser": "^4.1.0", - "resolve-from": "^5.0.0", - "slash": "^3.0.0", - "specificity": "^0.4.1", - "string-width": "^4.2.2", - "strip-ansi": "^6.0.0", - "style-search": "^0.1.0", - "sugarss": "^2.0.0", - "svg-tags": "^1.0.0", - "table": "^6.6.0", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" - }, - "bin": { - "stylelint": "bin/stylelint.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - } - }, - "node_modules/stylelint-config-recommended": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-4.0.0.tgz", - "integrity": "sha512-sgna89Ng+25Hr9kmmaIxpGWt2LStVm1xf1807PdcWasiPDaOTkOHRL61sINw0twky7QMzafCGToGDnHT/kTHtQ==", - "dev": true - }, - "node_modules/stylelint-config-standard": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-21.0.0.tgz", - "integrity": "sha512-Yf6mx5oYEbQQJxWuW7X3t1gcxqbUx52qC9SMS3saC2ruOVYEyqmr5zSW6k3wXflDjjFrPhar3kp68ugRopmlzg==", - "dev": true, - "dependencies": { - "stylelint-config-recommended": "^4.0.0" - } - }, - "node_modules/stylelint/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/stylelint/node_modules/autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", - "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", - "dev": true, - "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - }, - "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/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stylelint/node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "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/stylelint/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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/globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stylelint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/stylelint/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/stylelint/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/stylelint/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/stylelint/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" - } - }, - "node_modules/stylelint/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/stylelint/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" - } - }, - "node_modules/stylelint/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/stylelint/node_modules/postcss/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stylelint/node_modules/postcss/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stylelint/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/stylelint/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/stylelint/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stylelint/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stylelint/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/stylelint/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/sugarss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", - "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/sugarss/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sugarss/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sugarss/node_modules/postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/sugarss/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/sugarss/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/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/supports-hyperlinks/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/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", - "dev": true - }, - "node_modules/svg-to-pdfkit": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/svg-to-pdfkit/-/svg-to-pdfkit-0.1.8.tgz", - "integrity": "sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==", - "dependencies": { - "pdfkit": ">=0.8.1" - } - }, - "node_modules/svgo": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.3.1.tgz", - "integrity": "sha512-riDDIQgXpEnn0BEl9Gvhh1LNLIyiusSpt64IR8upJu7MwxnzetmF/Y57pXQD2NMX2lVyMRzXt5f2M5rO4wG7Dw==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.1.1", - "chalk": "^4.1.0", - "commander": "^7.1.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.2", - "csso": "^4.2.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/svgo/node_modules/css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", - "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", - "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/svgo/node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/svgo/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/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "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==" - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/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/table/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/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/table/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.4.tgz", - "integrity": "sha512-OdBCPgazNNsknSP+JfrPzkay9aqKjhKtFhbhgxHgvEFdHy/GuRPo2SCJ4w1SFTN8H6FPI4m6qD/Jj20NWY1GkA==", - "dev": true, - "dependencies": { - "@fullhuman/postcss-purgecss": "^4.0.3", - "arg": "^5.0.0", - "bytes": "^3.0.0", - "chalk": "^4.1.1", - "chokidar": "^3.5.2", - "color": "^3.1.3", - "cosmiconfig": "^7.0.0", - "detective": "^5.2.0", - "didyoumean": "^1.2.1", - "dlv": "^1.1.3", - "fast-glob": "^3.2.5", - "fs-extra": "^10.0.0", - "glob-parent": "^6.0.0", - "html-tags": "^3.1.0", - "is-glob": "^4.0.1", - "lodash": "^4.17.21", - "lodash.topath": "^4.5.2", - "modern-normalize": "^1.1.0", - "node-emoji": "^1.8.1", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss-js": "^3.0.3", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.5", - "postcss-selector-parser": "^6.0.6", - "postcss-value-parser": "^4.1.0", - "pretty-hrtime": "^1.0.3", - "quick-lru": "^5.1.1", - "reduce-css-calc": "^2.1.8", - "resolve": "^1.20.0", - "tmp": "^0.2.1" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "autoprefixer": "^10.0.2", - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "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/tailwindcss/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.0.tgz", - "integrity": "sha512-Hdd4287VEJcZXUwv1l8a+vXC1GjOQqXe+VS30w/ypihpcnu9M1n3xeYeJu5CBpeEQj2nAab2xxz28GuA3vp4Ww==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/tailwindcss/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tailwindcss/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/tailwindcss/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/tailwindcss/node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tailwindcss/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "node_modules/tailwindcss/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/tailwindcss/node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/tailwindcss/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/tape": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.13.3.tgz", - "integrity": "sha512-0/Y20PwRIUkQcTCSi4AASs+OANZZwqPKaipGCEwp10dQMipVvSZwUUCi01Y/OklIGyHKFhIcjock+DKnBfLAFw==", - "dependencies": { - "deep-equal": "~1.1.1", - "defined": "~1.0.0", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "function-bind": "~1.1.1", - "glob": "~7.1.6", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.0.5", - "minimist": "~1.2.5", - "object-inspect": "~1.7.0", - "resolve": "~1.17.0", - "resumer": "~0.0.0", - "string.prototype.trim": "~1.2.1", - "through": "~2.3.8" - }, - "bin": { - "tape": "bin/tape" - } - }, - "node_modules/tape/node_modules/is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dependencies": { - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/tape/node_modules/object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", - "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", - "dev": true, - "dependencies": { - "del": "^6.0.0", - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" - }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", - "dev": true - }, - "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-off-newlines": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz", - "integrity": "sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", - "dev": true - }, - "node_modules/tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "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" - } - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "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-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" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "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==" - }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-js/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-js/node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "node_modules/uglify-js/node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", - "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.0", - "has-symbols": "^1.0.0", - "which-boxed-primitive": "^1.0.1" - } - }, - "node_modules/unicode-properties": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.3.1.tgz", - "integrity": "sha512-nIV3Tf3LcUEZttY/2g4ZJtGXhWwSkuLL+rCu0DIAMbjyVPj+8j5gNVz4T/sVbnQybIsd5SFGkPKg/756OY6jlA==", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unified": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz", - "integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==", - "dev": true, - "dependencies": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - }, - "node_modules/unified/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unified/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "node_modules/uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/unist-util-find-all-after": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz", - "integrity": "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==", - "dev": true, - "dependencies": { - "unist-util-is": "^4.0.0" - } - }, - "node_modules/unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "dev": true - }, - "node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.2" - } - }, - "node_modules/universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "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/vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/venn.js": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", - "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", - "dependencies": { - "d3-selection": "^1.0.2", - "d3-transition": "^1.0.1", - "fmin": "0.0.2" - } - }, - "node_modules/vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - } - }, - "node_modules/vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "node_modules/vfile/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/vite": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.3.8.tgz", - "integrity": "sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.12.8", - "postcss": "^8.3.4", - "resolve": "^1.20.0", - "rollup": "^2.38.5" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": ">=12.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/vite-plugin-ruby": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vite-plugin-ruby/-/vite-plugin-ruby-2.0.4.tgz", - "integrity": "sha512-1YawT1DKSbY/N8OveNvhNuUOnXNgilMY38SzgLgTEIjIbauyvbArjKii3eK3JzmUcjr0rsPtKin7Omszhc/kvA==", - "dev": true, - "dependencies": { - "debug": "^4.3.1", - "fast-glob": "^3.2.4" - }, - "peerDependencies": { - "vite": ">=2.2.0" - } - }, - "node_modules/vite/node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-keyname": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", - "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "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/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/wmf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", - "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/word": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/word/-/word-0.4.0.tgz", - "integrity": "sha512-Aq84KjS7Z9HSU14qf4l/NEouaqfJAZtE9zEz7TIvw9V/3oJeUbjQwhz7ggqbL7I7REt4Bz+9HuCWsBO5N7xChw==", - "dependencies": { - "cfb": "^1.2.0", - "jsdom": "^16.2.2" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "engines": { - "node": ">=0.4.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" - } - }, - "node_modules/wrap-ansi/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/wrap-ansi/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" - } - }, - "node_modules/wrap-ansi/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/wrap-ansi/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/wrap-ansi/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/wrap-ansi/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "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/xlsx": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.17.2.tgz", - "integrity": "sha512-RIhN6/oc/ZqYZqY4jz4AX92yNfULhtNrcZP1lknIcsyR+Ra8Zu/9F1lAZWncYbDex95iYQX/XNNNzNFXZjlNOQ==", - "dependencies": { - "adler-32": "~1.2.0", - "cfb": "^1.1.4", - "codepage": "~1.15.0", - "commander": "~2.17.1", - "crc-32": "~1.2.0", - "exit-on-epipe": "~1.0.1", - "fflate": "^0.3.8", - "ssf": "~0.11.2", - "wmf": "~1.0.1", - "word": "~0.4.0" - }, - "bin": { - "xlsx": "bin/xlsx.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/xlsx/node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "node_modules/xmldoc": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-1.1.2.tgz", - "integrity": "sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ==", - "dependencies": { - "sax": "^1.2.1" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "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/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/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/yargs/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/yargs/node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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" - } - }, - "node_modules/zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", - "dev": true - } - }, - "dependencies": { - "@amcharts/amcharts4": { - "version": "4.10.22", - "resolved": "https://registry.npmjs.org/@amcharts/amcharts4/-/amcharts4-4.10.22.tgz", - "integrity": "sha512-Z/vPGKtNf1m4sdKK1P4San8SAG1AuYJ0tLhptUqntb4u+kRfRbU2QydIGsVmpHPENLg17ukIWySwo6mv3by/tw==", - "requires": { - "@babel/runtime": "^7.6.3", - "core-js": "^3.0.0", - "d3-force": "^2.0.1", - "d3-geo": "^2.0.1", - "d3-geo-projection": "^3.0.0", - "pdfmake": "^0.2.2", - "polylabel": "^1.0.2", - "raf": "^3.4.1", - "regression": "^2.0.1", - "rgbcolor": "^1.0.1", - "stackblur-canvas": "^2.0.0", - "tslib": "^2.0.1", - "venn.js": "^0.2.20", - "xlsx": "^0.17.0" - }, - "dependencies": { - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" - } - } - }, - "@amcharts/amcharts4-geodata": { - "version": "4.1.19", - "resolved": "https://registry.npmjs.org/@amcharts/amcharts4-geodata/-/amcharts4-geodata-4.1.19.tgz", - "integrity": "sha512-y100J6mp8H95qfHPPmeAat8oC+VXJrpt+rnwOt554sEW6cFCWY6BKgPKL2dVlVbnz0U3dqNsyENOqXmp3Pu7vg==" - }, - "@babel/code-frame": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", - "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.1" - } - }, - "@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", - "dev": true - }, - "@babel/core": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.10.tgz", - "integrity": "sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.10", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.10", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz", - "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-transforms": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz", - "integrity": "sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - } - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", - "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", - "dev": true, - "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "@babel/highlight": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", - "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.1", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@babel/parser": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.12.tgz", - "integrity": "sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==", - "dev": true - }, - "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", - "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.0", - "@babel/types": "^7.13.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@babel/types": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.12.tgz", - "integrity": "sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - } - } - }, - "@commitlint/cli": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-12.0.1.tgz", - "integrity": "sha512-V+cMYNHJOr40XT9Kvz3Vrz1Eh7QE1rjQrUbifawDAqcOrBJFuoXwU2SAcRtYFCSqFy9EhbreQGhZFs8dYb90KA==", - "dev": true, - "requires": { - "@commitlint/format": "^12.0.1", - "@commitlint/lint": "^12.0.1", - "@commitlint/load": "^12.0.1", - "@commitlint/read": "^12.0.1", - "@commitlint/types": "^12.0.1", - "get-stdin": "8.0.0", - "lodash": "^4.17.19", - "resolve-from": "5.0.0", - "resolve-global": "1.0.0", - "yargs": "^16.2.0" - }, - "dependencies": { - "@commitlint/execute-rule": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-12.0.1.tgz", - "integrity": "sha512-JzyweYfZlFLtXpgP+btzSY3YAkGPg61TqUSYQqBr4+5IaVf1FruMm5v4D5eLu9dAJuNKUfHbM3AEfuEPiZ79pg==", - "dev": true - }, - "@commitlint/load": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-12.0.1.tgz", - "integrity": "sha512-dX8KdCWn7w0bTkkk3zKQpe9X8vsTRa5EM+1ffF313wCX9b6tGa9vujhEHCkSzKAbbE2tFV64CHZygE7rtlHdIA==", - "dev": true, - "requires": { - "@commitlint/execute-rule": "^12.0.1", - "@commitlint/resolve-extends": "^12.0.1", - "@commitlint/types": "^12.0.1", - "chalk": "^4.0.0", - "cosmiconfig": "^7.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - } - }, - "@commitlint/resolve-extends": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-12.0.1.tgz", - "integrity": "sha512-Mvg0GDi/68Cqw893ha8uhxE8myHfPmiSSSi7d1x4VJNR4hoS37lBdX89kyx4i9NPmLfviY2cUJKTyK8ZrFznZw==", - "dev": true, - "requires": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - } - }, - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@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" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "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, - "requires": { - "@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" - } - }, - "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 - } - } - }, - "@commitlint/config-conventional": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-12.0.1.tgz", - "integrity": "sha512-1ZhB135lh47zVmf1orwcjxuKuam11fJIH/bdVxW9XiQv8XPwC6iIp19knfl8FcOT78AVBnes1z6EVxgUeP2/4Q==", - "dev": true, - "requires": { - "conventional-changelog-conventionalcommits": "^4.3.1" - } - }, - "@commitlint/ensure": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-12.0.1.tgz", - "integrity": "sha512-XdBq+q1YBBDxWIAEjE3Y1YMbzhUnUuSLAEWD8SU1xsvEpQXWRYwDlMBRkjO7funNWTdL0ZQSkZDzme70imYjbw==", - "dev": true, - "requires": { - "@commitlint/types": "^12.0.1", - "lodash": "^4.17.19" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - } - } - }, - "@commitlint/execute-rule": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-9.1.2.tgz", - "integrity": "sha512-NGbeo0KCVYo1yj9vVPFHv6RGFpIF6wcQxpFYUKGIzZVV9Vz1WyiKS689JXa99Dt1aN0cZlEJJLnTNDIgYls0Vg==", - "dev": true, - "optional": true - }, - "@commitlint/format": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-12.0.1.tgz", - "integrity": "sha512-rF79ipAxR8yFzPzG5tRoEZ//MRkyxCXj4JhpEjtdaCMBAXMssI8uazn3e5D8z4UFgSDe9qOnL0OmQvql7HTMoA==", - "dev": true, - "requires": { - "@commitlint/types": "^12.0.1", - "chalk": "^4.0.0" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - } - } - }, - "@commitlint/is-ignored": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-12.0.1.tgz", - "integrity": "sha512-AplfLn5mX/kWTIiSolcOhTYcgphuGLX8FUr+HmyHBEqUkO36jt0z9caysH47fqU71ePtH63v1DWm+RYQ5RPDjg==", - "dev": true, - "requires": { - "@commitlint/types": "^12.0.1", - "semver": "7.3.4" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@commitlint/lint": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-12.0.1.tgz", - "integrity": "sha512-1lKyRCq4ahJrY+Xxo8LsqCbALeJkodtEfpmYHeA5HpPMnK7lRSplLqOLcTCjoPfd4vO+gl6aDEZN+ow3YGQBOg==", - "dev": true, - "requires": { - "@commitlint/is-ignored": "^12.0.1", - "@commitlint/parse": "^12.0.1", - "@commitlint/rules": "^12.0.1", - "@commitlint/types": "^12.0.1" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - } - } - }, - "@commitlint/load": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-9.1.2.tgz", - "integrity": "sha512-FPL82xBuF7J3EJ57kLVoligQP4BFRwrknooP+vNT787AXmQ/Fddc/iYYwHwy67pNkk5N++/51UyDl/CqiHb6nA==", - "dev": true, - "optional": true, - "requires": { - "@commitlint/execute-rule": "^9.1.2", - "@commitlint/resolve-extends": "^9.1.2", - "@commitlint/types": "^9.1.2", - "chalk": "4.1.0", - "cosmiconfig": "^6.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "optional": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "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, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "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, - "optional": true - }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "optional": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "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, - "optional": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "optional": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "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, - "optional": true - } - } - }, - "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "optional": true, - "requires": { - "@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" - } - }, - "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, - "optional": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@commitlint/message": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-12.0.1.tgz", - "integrity": "sha512-fXuoxRC+NT1wEQi6p8oHfT7wvWIRgTk+udlRJnWTjmMpiYzVnMmmZfasdShirWr4TtxQtMyL+5DVgh7Y98kURw==", - "dev": true - }, - "@commitlint/parse": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-12.0.1.tgz", - "integrity": "sha512-7oEGASmzBnHir5jSIR7KephXrKh7rIi9a6RpH1tOT+CIENYvhe8EDtIy29qMt+RLa2LlaPF7YrAgaJRfzG0YDQ==", - "dev": true, - "requires": { - "@commitlint/types": "^12.0.1", - "conventional-changelog-angular": "^5.0.11", - "conventional-commits-parser": "^3.0.0" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - } - } - }, - "@commitlint/read": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-12.0.1.tgz", - "integrity": "sha512-baa0YeD4QOctEuthLpExQSi9xPiw0kDPfUVHqp8I88iuIXJECeS8S1+1GBiz89e8dLN9zmEE+sN9vtJHdAp9YA==", - "dev": true, - "requires": { - "@commitlint/top-level": "^12.0.1", - "@commitlint/types": "^12.0.1", - "fs-extra": "^9.0.0", - "git-raw-commits": "^2.0.0" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "@commitlint/resolve-extends": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-9.1.2.tgz", - "integrity": "sha512-HcoL+qFGmWEu9VM4fY0HI+VzF4yHcg3x+9Hx6pYFZ+r2wLbnKs964y0v68oyMO/mS/46MVoLNXZGR8U3adpadg==", - "dev": true, - "optional": true, - "requires": { - "import-fresh": "^3.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0", - "resolve-global": "^1.0.0" - }, - "dependencies": { - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "optional": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "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, - "optional": true - } - } - }, - "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, - "optional": true - } - } - }, - "@commitlint/rules": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-12.0.1.tgz", - "integrity": "sha512-A5O0ubNGugZR9WWxk5IVOLo07lpdUwhG5WkAW2lYpgZ7Z/2U4PLob9b4Ih1eHbQu+gnVeFr91k7F0DrpM7B8EQ==", - "dev": true, - "requires": { - "@commitlint/ensure": "^12.0.1", - "@commitlint/message": "^12.0.1", - "@commitlint/to-lines": "^12.0.1", - "@commitlint/types": "^12.0.1" - }, - "dependencies": { - "@commitlint/types": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-12.0.1.tgz", - "integrity": "sha512-FsNDMV0W7D19/ZbR412klpqAilXASx75Neqh7jPtK278IEwdukOg3vth1r5kTm+BjDScM7wMUEOwIW3NNfAtwg==", - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - } - } - }, - "@commitlint/to-lines": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-12.0.1.tgz", - "integrity": "sha512-XwcJ1jY7x2fhudzbGMpNQkTSMVrxWrI8bRMbVe3Abuu7RfYpFf7VXAlhtnLfxBoagaK7RxjC2+eRidp/3txQBg==", - "dev": true - }, - "@commitlint/top-level": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-12.0.1.tgz", - "integrity": "sha512-rHdgt7U24GEau2/9i2vEAbksxkBRiVjHj5ECFL5dd0AJOIvaK++vMg4EF/ME0X/1yd9qVTHTNOl2Q4tTFK7VBQ==", - "dev": true, - "requires": { - "find-up": "^5.0.0" - }, - "dependencies": { - "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, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "p-locate": "^5.0.0" - } - }, - "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, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "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, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "@commitlint/types": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", - "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", - "dev": true, - "optional": true - }, - "@csstools/convert-colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", - "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", - "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "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 - }, - "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 - }, - "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 - } - } - }, - "@foliojs-fork/fontkit": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.1.tgz", - "integrity": "sha512-U589voc2/ROnvx1CyH9aNzOQWJp127JGU1QAylXGQ7LoEAF6hMmahZLQ4eqAcgHUw+uyW4PjtCItq9qudPkK3A==", - "requires": { - "@foliojs-fork/restructure": "^2.0.2", - "brfs": "^2.0.0", - "brotli": "^1.2.0", - "browserify-optional": "^1.0.1", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "^1.2.0", - "tiny-inflate": "^1.0.2", - "unicode-properties": "^1.2.2", - "unicode-trie": "^2.0.0" - } - }, - "@foliojs-fork/linebreak": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.1.tgz", - "integrity": "sha512-pgY/+53GqGQI+mvDiyprvPWgkTlVBS8cxqee03ejm6gKAQNsR1tCYCIvN9FHy7otZajzMqCgPOgC4cHdt4JPig==", - "requires": { - "base64-js": "1.3.1", - "brfs": "^2.0.2", - "unicode-trie": "^2.0.0" - } - }, - "@foliojs-fork/pdfkit": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.12.3.tgz", - "integrity": "sha512-WAMiL5Dp1EdHyuEeVphiqVeFEaccGShS5wLcuOXFF0wlBE5agkvTEk3sJ2OfAn87FaStpkuiaiSKNRexMlNHUA==", - "requires": { - "@foliojs-fork/fontkit": "^1.9.1", - "@foliojs-fork/linebreak": "^1.1.1", - "crypto-js": "^4.0.0", - "png-js": "^1.0.0" - } - }, - "@foliojs-fork/restructure": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz", - "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==" - }, - "@fullhuman/postcss-purgecss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-4.0.3.tgz", - "integrity": "sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==", - "dev": true, - "requires": { - "purgecss": "^4.0.3" - } - }, - "@lit/reactive-element": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0-rc.2.tgz", - "integrity": "sha512-cujeIl5Ei8FC7UHf4/4Q3bRJOtdTe1vpJV/JEBYCggedmQ+2P8A2oz7eE+Vxi6OJ4nc0X+KZxXnBoH4QrEbmEQ==" - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", - "dev": true, - "requires": { - "@octokit/types": "^6.0.3" - } - }, - "@octokit/core": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz", - "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", - "dev": true, - "requires": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.0", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", - "dev": true, - "requires": { - "@octokit/types": "^6.0.3", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" - }, - "dependencies": { - "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==", - "dev": true - } - } - }, - "@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", - "dev": true, - "requires": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", - "universal-user-agent": "^6.0.0" - } - }, - "@octokit/openapi-types": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", - "dev": true - }, - "@octokit/plugin-paginate-rest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", - "dev": true, - "requires": { - "@octokit/types": "^6.34.0" - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", - "dev": true, - "requires": {} - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", - "dev": true, - "requires": { - "@octokit/types": "^6.34.0", - "deprecation": "^2.3.1" - } - }, - "@octokit/request": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz", - "integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==", - "dev": true, - "requires": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.1", - "universal-user-agent": "^6.0.0" - }, - "dependencies": { - "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==", - "dev": true - } - } - }, - "@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", - "dev": true, - "requires": { - "@octokit/types": "^6.0.3", - "deprecation": "^2.0.0", - "once": "^1.4.0" - } - }, - "@octokit/rest": { - "version": "18.12.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", - "dev": true, - "requires": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" - } - }, - "@octokit/types": { - "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", - "dev": true, - "requires": { - "@octokit/openapi-types": "^11.2.0" - } - }, - "@popperjs/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", - "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==" - }, - "@rollup/plugin-multi-entry": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-multi-entry/-/plugin-multi-entry-4.0.0.tgz", - "integrity": "sha512-1Sw86rwFxrNS7ECY3iSZ7T940xKnruNGpmQDgSDVTp+VTa1g5cPXNzBgp+IoOer41CiVeGFLwYwvicVoJLHEDQ==", - "requires": { - "@rollup/plugin-virtual": "^2.0.3", - "matched": "^5.0.0" - } - }, - "@rollup/plugin-virtual": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-2.0.3.tgz", - "integrity": "sha512-pw6ziJcyjZtntQ//bkad9qXaBx665SgEL8C8KI5wO8G5iU5MPxvdWrQyVaAvjojGm9tJoS8M9Z/EEepbqieYmw==", - "requires": {} - }, - "@semantic-release/changelog": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.1.tgz", - "integrity": "sha512-FT+tAGdWHr0RCM3EpWegWnvXJ05LQtBkQUaQRIExONoXjVjLuOILNm4DEKNaV+GAQyJjbLRVs57ti//GypH6PA==", - "dev": true, - "requires": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "fs-extra": "^9.0.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^1.0.0" - } - }, - "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" - } - }, - "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", - "dev": true - } - } - }, - "@semantic-release/commit-analyzer": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.1.tgz", - "integrity": "sha512-ncNsnrLmiykhgNZUXNvhhAjNN0me7VGIb0X5hu3ogyi5DDPapjGAHdEffO5vi+HX1BFWLRD/Ximx5PjGAKjAqQ==", - "dev": true, - "requires": { - "conventional-changelog-angular": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.0.7", - "debug": "^4.0.0", - "import-from": "^4.0.0", - "lodash": "^4.17.4", - "micromatch": "^4.0.2" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "import-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", - "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", - "dev": true - }, - "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 - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "@semantic-release/error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", - "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", - "dev": true - }, - "@semantic-release/exec": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/exec/-/exec-6.0.2.tgz", - "integrity": "sha512-ciaqJTHB1TFtU6C78xrgmoNI9UyfheR9+Bk6Ico7CJ7+ADOEAvUrPBKvz64UCfoWlg+SlKGTVGbFnA509wRUVw==", - "dev": true, - "requires": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "execa": "^5.0.0", - "lodash": "^4.17.4", - "parse-json": "^5.0.0" - }, - "dependencies": { - "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "requires": { - "@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" - } - } - } - }, - "@semantic-release/git": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", - "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", - "dev": true, - "requires": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "execa": "^5.0.0", - "lodash": "^4.17.4", - "micromatch": "^4.0.0", - "p-reduce": "^2.0.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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 - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "@semantic-release/github": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.2.tgz", - "integrity": "sha512-wIbfhOeuxlYzMTjtSAa2xgr54n7ZuPAS2gadyTWBpUt2PNAPgla7A6XxCXJnaKPgfVF0iFfSk3B+KlVKk6ByVg==", - "dev": true, - "requires": { - "@octokit/rest": "^18.0.0", - "@semantic-release/error": "^2.2.0", - "aggregate-error": "^3.0.0", - "bottleneck": "^2.18.1", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "issue-parser": "^6.0.0", - "lodash": "^4.17.4", - "mime": "^3.0.0", - "p-filter": "^2.0.0", - "p-retry": "^4.0.0", - "url-join": "^4.0.0" - }, - "dependencies": { - "@semantic-release/error": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", - "dev": true - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "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, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "@semantic-release/gitlab": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@semantic-release/gitlab/-/gitlab-7.0.4.tgz", - "integrity": "sha512-TL6kT526+ir/uehMFdTlJNXUj+p+SjPAYUkit6lh5Rs8kxeHQ01bgmpYLQlc94ZDpy9x2Tzcb/NRwKojkmLG4A==", - "dev": true, - "requires": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "escape-string-regexp": "^3.0.0", - "form-data": "^4.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "got": "^11.0.0", - "lodash": "^4.17.11", - "parse-path": "^4.0.0", - "url-join": "^4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-3.0.0.tgz", - "integrity": "sha512-11dXIUC3umvzEViLP117d0KN6LJzZxh5+9F4E/7WLAAw7GrHk8NpUR+g9iJi/pe9C0py4F8rs0hreyRCwlAuZg==", - "dev": true - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "@semantic-release/npm": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-8.0.3.tgz", - "integrity": "sha512-Qbg7x/O1t3sJqsv2+U0AL4Utgi/ymlCiUdt67Ftz9HL9N8aDML4t2tE0T9MBaYdqwD976hz57DqHHXKVppUBoA==", - "dev": true, - "requires": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.0", - "lodash": "^4.17.15", - "nerf-dart": "^1.0.0", - "normalize-url": "^6.0.0", - "npm": "^7.0.0", - "rc": "^1.2.8", - "read-pkg": "^5.0.0", - "registry-auth-token": "^4.0.0", - "semver": "^7.1.2", - "tempy": "^1.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "@semantic-release/release-notes-generator": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.2.tgz", - "integrity": "sha512-I4eavIcDan8fNQHskZ2cbWkFMimvgxNkqR2UfuYNwYBgswEl3SJsN8XMf9gZWObt6nXDc2QfDwhjy8DjTZqS3w==", - "dev": true, - "requires": { - "conventional-changelog-angular": "^5.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.0.0", - "debug": "^4.0.0", - "get-stream": "^6.0.0", - "import-from": "^4.0.0", - "into-stream": "^6.0.0", - "lodash": "^4.17.4", - "read-pkg-up": "^7.0.0" - }, - "dependencies": { - "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 - }, - "import-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", - "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", - "dev": true - } - } - }, - "@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", - "dev": true - }, - "@stylelint/postcss-css-in-js": { - "version": "0.37.2", - "resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz", - "integrity": "sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA==", - "dev": true, - "requires": { - "@babel/core": ">=7.9.0" - } - }, - "@stylelint/postcss-markdown": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz", - "integrity": "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==", - "dev": true, - "requires": { - "remark": "^13.0.0", - "unist-util-find-all-after": "^3.0.2" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@tailwindcss/forms": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.2.1.tgz", - "integrity": "sha512-czfvEdY+J2Ogfd6RUSr/ZSUmDxTujr34M++YLnp2cCPC3oJ4kFvFMaRXA6cEXKw7F1hJuapdjXRjsXIEXGgORg==", - "dev": true, - "requires": { - "mini-svg-data-uri": "^1.2.3" - } - }, - "@tailwindcss/line-clamp": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.2.0.tgz", - "integrity": "sha512-+jXSdRK3/9V/BCPCr+iNpMMhxWMMv62vn/AS2b3/ClmueGuhCijW3bUwO1IiHnE7uCaF74Sli8jUCv9djwvpLg==", - "dev": true - }, - "@tailwindcss/typography": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.4.0.tgz", - "integrity": "sha512-3BfOYT5MYNEq81Ism3L2qu/HRP2Q5vWqZtZRQqQrthHuaTK9qpuPfbMT5WATjAM5J1OePKBaI5pLoX4S1JGNMQ==", - "dev": true, - "requires": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "lodash.uniq": "^4.5.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, - "@trysound/sax": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz", - "integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==", - "dev": true - }, - "@types/cacheable-request": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", - "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/geojson": { - "version": "7946.0.8", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", - "dev": true - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/highlight.js": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", - "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", - "dev": true - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "@types/keyv": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", - "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/leaflet": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.5.tgz", - "integrity": "sha512-+Myo00Yb5OuvUyrH+vUwn9DRgOaBJsF/etIMdMcNhWGBMo58Mo1cxLInvCd0ZpvItju/AeDYFB/Od2pLiHB3VA==", - "dev": true, - "requires": { - "@types/geojson": "*" - } - }, - "@types/linkify-it": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.0.tgz", - "integrity": "sha512-x9OaQQTb1N2hPZ/LWJsqushexDvz7NgzuZxiRmZio44WPuolTZNHDBCrOxCzRVOMwamJRO2dWax5NbygOf1OTQ==", - "dev": true - }, - "@types/markdown-it": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.0.1.tgz", - "integrity": "sha512-mHfT8j/XkPb1uLEfs0/C3se6nd+webC2kcqcy8tgcVr0GDEONv/xaQzAN+aQvkxQXk/jC0Q6mPS+0xhFwRF35g==", - "dev": true, - "requires": { - "@types/highlight.js": "^9.7.0", - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "@types/mdast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz", - "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==", - "dev": true, - "requires": { - "@types/unist": "*" - } - }, - "@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", - "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", - "dev": true - }, - "@types/node": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.1.tgz", - "integrity": "sha512-HnYlg/BRF8uC1FyKRFZwRaCPTPYKa+6I8QiUZFLredaGOou481cgFS4wKRFyKvQtX8xudqkSdBczJHIYSQYKrQ==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/orderedmap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz", - "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw==", - "dev": true - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "@types/prosemirror-markdown": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@types/prosemirror-markdown/-/prosemirror-markdown-1.5.1.tgz", - "integrity": "sha512-AqHCy80J9HUF+9FHveOB9fbKZwOf+1Ds2Vm1pPN6bfZ/Y6vdgXDry/hoz74+K7fQZZ8+f1J4x16llFj3PAohVg==", - "dev": true, - "requires": { - "@types/markdown-it": "*", - "@types/prosemirror-model": "*" - } - }, - "@types/prosemirror-model": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.11.2.tgz", - "integrity": "sha512-mohs15V+gxj10QWJGVooErzSE9ryTo1Wy92lULiQ0BSN5Po9K4vngPzfKmLft0+gAPbEghovTX+I2zQW3bZo1w==", - "dev": true, - "requires": { - "@types/orderedmap": "*" - } - }, - "@types/prosemirror-state": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.2.6.tgz", - "integrity": "sha512-tJo0wC+/cQvbrPDVx01Fnng9Fs41bAMVxgJY1KLOyIsUPN0otUN1KdoQurLMmHNHTvIna9ZXxjZD//xJKLYfJw==", - "dev": true, - "requires": { - "@types/prosemirror-model": "*", - "@types/prosemirror-transform": "*", - "@types/prosemirror-view": "*" - } - }, - "@types/prosemirror-transform": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/prosemirror-transform/-/prosemirror-transform-1.1.2.tgz", - "integrity": "sha512-Ozyvs5Dquc49gaFysmC4gNhv6E65r569HSzw4RXdZgIljZ5Y9K4kHFlDvsWBBDH19+1178X9LMmM9J620O6Bug==", - "dev": true, - "requires": { - "@types/prosemirror-model": "*" - } - }, - "@types/prosemirror-view": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/prosemirror-view/-/prosemirror-view-1.17.1.tgz", - "integrity": "sha512-PNiGGc6BffxHQzMR09UUilsBR8xFPDsKiPIXb4K/g56voPIvqq1pqySnWFfSR50Vo4ZL0tss3VBLWiiiKzVahQ==", - "dev": true, - "requires": { - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-transform": "*" - } - }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", - "dev": true - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "@types/trusted-types": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz", - "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==" - }, - "@types/unist": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", - "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.19.0.tgz", - "integrity": "sha512-CRQNQ0mC2Pa7VLwKFbrGVTArfdVDdefS+gTw0oC98vSI98IX5A8EVH4BzJ2FOB0YlCmm8Im36Elad/Jgtvveaw==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.19.0", - "@typescript-eslint/scope-manager": "4.19.0", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.15", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.19.0.tgz", - "integrity": "sha512-9/23F1nnyzbHKuoTqFN1iXwN3bvOm/PRIXSBR3qFAYotK/0LveEOHr5JT1WZSzcD6BESl8kPOG3OoDRKO84bHA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.19.0.tgz", - "integrity": "sha512-/uabZjo2ZZhm66rdAu21HA8nQebl3lAIDcybUoOxoI7VbZBYavLIwtOOmykKCJy+Xq6Vw6ugkiwn8Js7D6wieA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.19.0", - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/typescript-estree": "4.19.0", - "debug": "^4.1.1" - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.19.0.tgz", - "integrity": "sha512-GGy4Ba/hLXwJXygkXqMzduqOMc+Na6LrJTZXJWVhRrSuZeXmu8TAnniQVKgj8uTRKe4igO2ysYzH+Np879G75g==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0" - } - }, - "@typescript-eslint/types": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.19.0.tgz", - "integrity": "sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz", - "integrity": "sha512-3xqArJ/A62smaQYRv2ZFyTA+XxGGWmlDYrsfZG68zJeNbeqRScnhf81rUVa6QG4UgzHnXw5VnMT5cg75dQGDkA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.19.0", - "@typescript-eslint/visitor-keys": "4.19.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.19.0.tgz", - "integrity": "sha512-aGPS6kz//j7XLSlgpzU2SeTqHPsmRYxFztj2vPuMMFJXZudpRSehE3WCV+BaxwZFvfAqMoSd86TEuM0PQ59E/A==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.19.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" - }, - "adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - } - }, - "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==", - "requires": { - "debug": "4" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - } - } - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.0.tgz", - "integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "argv-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", - "dev": true - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" - }, - "array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "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 - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=", - "requires": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" - }, - "dependencies": { - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" - } - } - }, - "ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=" - }, - "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 - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "autoprefixer": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.6.tgz", - "integrity": "sha512-8lChSmdU6dCNMCQopIf4Pe5kipkAGj/fvTMslCsih0uHpOrXOPUEVOmYMMqmw3cekQkSD7EhIeuYl5y0BLdKqg==", - "dev": true, - "peer": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-lite": "^1.0.30001230", - "colorette": "^1.2.2", - "fraction.js": "^4.1.1", - "normalize-range": "^0.1.2", - "postcss-value-parser": "^4.1.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } - } - }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "before-after-hook": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", - "dev": true - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brfs": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", - "integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==", - "requires": { - "quote-stream": "^1.0.1", - "resolve": "^1.1.5", - "static-module": "^3.0.2", - "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "brotli": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.2.tgz", - "integrity": "sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y=", - "requires": { - "base64-js": "^1.1.2" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - } - } - }, - "browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=", - "requires": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" - } - }, - "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - } - }, - "buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=" - }, - "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==" - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - } - } - }, - "cachedir": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.2.0.tgz", - "integrity": "sha512-VvxA0xhNqIIfg0V9AmJkDg91DaJwryutH5rVEZAhcNi4iJFj9f+QxmAjgK1LT9I8OgToX27fypX6/MeCXVbBjQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true - }, - "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, - "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - } - }, - "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, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001242", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", - "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==", - "dev": true - }, - "cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", - "dev": true, - "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - } - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "cfb": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.1.tgz", - "integrity": "sha512-wT2ScPAFGSVy7CY+aauMezZBnNrfnaLSrxHUHdea+Td/86vrk6ZquggV+ssBR88zNs0OnBkL2+lf9q0K+zVGzQ==", - "requires": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0", - "printj": "~1.3.0" - }, - "dependencies": { - "adler-32": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.0.tgz", - "integrity": "sha512-f5nltvjl+PRUh6YNfUstRaXwJxtfnKEWhAWWlmKvh+Y3J2+98a0KKVYDEhz6NdKGqswLhjNGznxfSsZGOvOd9g==", - "requires": { - "printj": "~1.2.2" - }, - "dependencies": { - "printj": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.2.3.tgz", - "integrity": "sha512-sanczS6xOJOg7IKDvi4sGOUOe7c1tsEzjwlLFH/zgwx/uyImVM9/rgBkc8AfiQa/Vg54nRd8mkm9yI7WV/O+WA==" - } - } - }, - "printj": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.0.tgz", - "integrity": "sha512-017o8YIaz8gLhaNxRB9eBv2mWXI2CtzhPJALnQTP+OPpuUfP0RMWqr/mHCzqVeu1AQxfzSfAtAq66vKB8y7Lzg==" - } - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true - }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true - }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "requires": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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 - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "ci-info": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.1.1.tgz", - "integrity": "sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", - "requires": { - "exit": "0.1.2", - "glob": "^7.1.1" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", - "dev": true, - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "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 - }, - "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 - }, - "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, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "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, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "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 - }, - "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 - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "clone-regexp": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz", - "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==", - "dev": true, - "requires": { - "is-regexp": "^2.0.0" - }, - "dependencies": { - "is-regexp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz", - "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==", - "dev": true - } - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "codepage": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", - "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", - "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.4" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "commitizen": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.4.tgz", - "integrity": "sha512-LlZChbDzg3Ir3O2S7jSo/cgWp5/QwylQVr59K4xayVq8S4/RdKzSyJkghAiZZHfhh5t4pxunUoyeg0ml1q/7aw==", - "dev": true, - "requires": { - "cachedir": "2.2.0", - "cz-conventional-changelog": "3.2.0", - "dedent": "0.7.0", - "detect-indent": "6.0.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "8.1.0", - "glob": "7.1.4", - "inquirer": "6.5.2", - "is-utf8": "^0.2.1", - "lodash": "^4.17.20", - "minimist": "1.2.5", - "strip-bom": "4.0.0", - "strip-json-comments": "3.0.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cz-conventional-changelog": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.2.0.tgz", - "integrity": "sha512-yAYxeGpVi27hqIilG1nh4A9Bnx4J3Ov+eXy4koL3drrR+IO9GaWPsKjik20ht608Asqi8TQPf0mczhEeyAtMzg==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-node-modules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.2.tgz", - "integrity": "sha512-x+3P4mbtRPlSiVE1Qco0Z4YLU8WFiFcuWTf3m75OV9Uzcfs2Bg+O9N+r/K0AnmINBW06KpfqKwYJbFlFq4qNug==", - "dev": true, - "requires": { - "findup-sync": "^4.0.0", - "merge": "^2.1.0" - } - }, - "findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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 - }, - "merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "requires": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "requires": { - "date-now": "^0.1.4" - } - }, - "contour_plot": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", - "integrity": "sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=" - }, - "conventional-changelog-angular": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", - "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "q": "^1.5.1" - } - }, - "conventional-changelog-conventionalcommits": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz", - "integrity": "sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - } - }, - "conventional-changelog-writer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz", - "integrity": "sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g==", - "dev": true, - "requires": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.6", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - } - }, - "conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", - "dev": true - }, - "conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", - "dev": true, - "requires": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - } - }, - "conventional-commits-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", - "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", - "dev": true, - "requires": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0", - "trim-off-newlines": "^1.0.0" - } - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - } - }, - "cp-file": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", - "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "nested-error-stacks": "^2.0.0", - "p-event": "^4.1.0" - } - }, - "cpy": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz", - "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==", - "dev": true, - "requires": { - "arrify": "^2.0.1", - "cp-file": "^7.0.0", - "globby": "^9.2.0", - "has-glob": "^1.0.0", - "junk": "^3.1.0", - "nested-error-stacks": "^2.1.0", - "p-all": "^2.1.0", - "p-filter": "^2.1.0", - "p-map": "^3.0.0" - }, - "dependencies": { - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true - }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, - "requires": { - "path-type": "^3.0.0" - } - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } - } - }, - "cpy-cli": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-3.1.1.tgz", - "integrity": "sha512-HCpNdBkQy3rw+uARLuIf0YurqsMXYzBa9ihhSAuxYJcNIrqrSq3BstPfr0cQN38AdMrQiO9Dp4hYy7GtGJsLPg==", - "dev": true, - "requires": { - "cpy": "^8.0.0", - "meow": "^6.1.1" - }, - "dependencies": { - "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 - }, - "meow": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", - "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "^4.0.2", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, - "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, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "crc-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", - "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - } - }, - "crelt": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.4.tgz", - "integrity": "sha512-l1cwMUOssGLEj5zgbut4lxJq95ZabOXVZnDybNqQRUtXh1lvUK7e7kJNm8SfvTQzYpE3AVJhIVUJKf382lMA7A==" - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "css-blank-pseudo": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", - "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", - "dev": true, - "requires": { - "postcss": "^7.0.5" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dev": true, - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "css-has-pseudo": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", - "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", - "dev": true, - "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^5.0.0-rc.4" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "css-prefers-color-scheme": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", - "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", - "dev": true, - "requires": { - "postcss": "^7.0.5" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } - } - }, - "css-unit-converter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", - "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==", - "dev": true - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true - }, - "cssdb": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", - "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==", - "dev": true - }, - "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 - }, - "cssnano": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - } - } - }, - "cz-conventional-changelog": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", - "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "requires": { - "internmap": "^1.0.0" - } - }, - "d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "d3-dispatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", - "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" - }, - "d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "d3-force": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-2.1.1.tgz", - "integrity": "sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==", - "requires": { - "d3-dispatch": "1 - 2", - "d3-quadtree": "1 - 2", - "d3-timer": "1 - 2" - } - }, - "d3-geo": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-2.0.1.tgz", - "integrity": "sha512-M6yzGbFRfxzNrVhxDJXzJqSLQ90q1cCyb3EWFZ1LF4eWOBYxFypw7I/NFVBNXKNqxv1bqLathhYvdJ6DC+th3A==", - "requires": { - "d3-array": ">=2.5" - } - }, - "d3-geo-projection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-3.0.0.tgz", - "integrity": "sha512-1JE+filVbkEX2bT25dJdQ05iA4QHvUwev6o0nIQHOSrNlHCAKfVss/U10vEM3pA4j5v7uQoFdQ4KLbx9BlEbWA==", - "requires": { - "commander": "2", - "d3-array": "1 - 2", - "d3-geo": "1.12.0 - 2", - "resolve": "^1.1.10" - }, - "dependencies": { - "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==" - } - } - }, - "d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "requires": { - "d3-color": "1" - } - }, - "d3-quadtree": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-2.0.0.tgz", - "integrity": "sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==" - }, - "d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" - }, - "d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" - }, - "d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - }, - "dependencies": { - "d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" - } - } - }, - "dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true - }, - "dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - } - } - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "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 - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" - }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", - "dev": true - }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "dfa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" - }, - "didyoumean": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz", - "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=", - "dev": true - }, - "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, - "requires": { - "path-type": "^4.0.0" - } - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", - "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" - } - } - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "requires": { - "minimatch": "^3.0.4" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "requires": { - "readable-stream": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.3.766", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz", - "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w==", - "dev": true - }, - "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 - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "env-ci": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.4.1.tgz", - "integrity": "sha512-xyuCtyFZLpnW5aH0JstETKTSMwHHQX4m42juzEZzvbUCJX7RiPVlhASKM0f/cJ4vvI/+txMkZ7F5To6dCdPYhg==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "fromentries": "^1.3.2", - "java-properties": "^1.0.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - } - } - }, - "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - } - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "esbuild": { - "version": "0.12.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.12.tgz", - "integrity": "sha512-fdB/8HRg9u95Zi4/qV+osrfzpvLzubFKUr8SkZf/kUKImLiX61Y7qBzV14FCKphFk7YoXWY85nbPGkI6pq+Zeg==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=", - "requires": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0", - "source-map": "~0.1.30" - }, - "dependencies": { - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" - }, - "estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=" - }, - "esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=" - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "eslint": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz", - "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.21", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.4", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "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 - }, - "globals": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", - "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "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 - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "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 - }, - "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 - } - } - }, - "eslint-config-prettier": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", - "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", - "dev": true - }, - "eslint-plugin-prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", - "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "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, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "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, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "estree-is-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/estree-is-function/-/estree-is-function-1.0.0.tgz", - "integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "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 - }, - "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 - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - } - } - }, - "execall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", - "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", - "dev": true, - "requires": { - "clone-regexp": "^2.1.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" - }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "ext": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.5.0.tgz", - "integrity": "sha512-+ONcYoWj/SoQwUofMr94aGu05Ou4FepKi7N7b+O8T4jVfyIsZQV1/xeS8jpaBzF0csAk0KLXoHCxU7cKYZjo1Q==", - "requires": { - "type": "^2.5.0" - }, - "dependencies": { - "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "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 - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", - "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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 - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "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 - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fflate": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz", - "integrity": "sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A==" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "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, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", - "dev": true, - "requires": { - "semver-regex": "^3.1.2" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatpickr": { - "version": "4.6.9", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", - "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==" - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "flatten": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", - "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", - "dev": true - }, - "fmin": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", - "integrity": "sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=", - "requires": { - "contour_plot": "^0.0.1", - "json2module": "^0.0.3", - "rollup": "^0.25.8", - "tape": "^4.5.1", - "uglify-js": "^2.6.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "rollup": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", - "integrity": "sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=", - "requires": { - "chalk": "^1.1.1", - "minimist": "^1.2.0", - "source-map-support": "^0.3.2" - } - }, - "source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "source-map-support": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", - "integrity": "sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=", - "requires": { - "source-map": "0.1.32" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "fontkit": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.8.1.tgz", - "integrity": "sha512-BsNCjDoYRxmNWFdAuK1y9bQt+igIxGtTC9u/jSFjR9MKhmI00rP1fwSvERt+5ddE82544l0XH5mzXozQVUy2Tw==", - "requires": { - "babel-runtime": "^6.26.0", - "brfs": "^2.0.0", - "brotli": "^1.2.0", - "browserify-optional": "^1.0.1", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "^1.2.0", - "restructure": "^0.5.3", - "tiny-inflate": "^1.0.2", - "unicode-properties": "^1.2.2", - "unicode-trie": "^0.3.0" - }, - "dependencies": { - "unicode-trie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", - "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", - "requires": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - } - } - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" - }, - "fraction.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz", - "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==", - "dev": true, - "peer": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" - }, - "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 - }, - "get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" - }, - "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 - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true - }, - "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, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "git-log-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", - "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", - "dev": true, - "requires": { - "argv-formatter": "~1.0.0", - "spawn-error-forwarder": "~1.0.0", - "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "~0.6.6" - }, - "dependencies": { - "split2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", - "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", - "dev": true, - "requires": { - "through2": "~2.0.0" - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "git-raw-commits": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", - "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", - "dev": true, - "requires": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", - "dev": true - }, - "gonzales-pe": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", - "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "got": { - "version": "11.8.3", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", - "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "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 - }, - "uglify-js": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", - "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "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 - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", - "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=", - "dev": true, - "requires": { - "is-glob": "^3.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hook-std": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", - "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", - "dev": true - }, - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", - "dev": true - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "dependencies": { - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - } - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "husky": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", - "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", - "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", - "dev": true, - "requires": { - "import-from": "^3.0.0" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", - "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "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 - } - } - }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "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 - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "requires": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - } - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - }, - "is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==" - }, - "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, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" - }, - "is-ci": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", - "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", - "dev": true, - "requires": { - "ci-info": "^3.1.1" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "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 - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "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, - "requires": { - "isobject": "^3.0.1" - } - }, - "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==" - }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-ssh": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", - "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", - "dev": true, - "requires": { - "protocols": "^1.1.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, - "requires": { - "text-extensions": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "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 - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", - "dev": true, - "requires": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" - } - }, - "java-properties": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "jshint": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.1.tgz", - "integrity": "sha512-vymzfR3OysF5P774x6zYv0bD4EpH6NWRxpq54wO9mA9RuY49yb1teKSICkLx2Ryx+mfzlVVNNbTBtsRtg78t7g==", - "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.21", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - }, - "dependencies": { - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" - }, - "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=" - } - } - }, - "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 - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.0.tgz", - "integrity": "sha512-o3aP+RsWDJZayj1SbHNQAI8x0v3T3SKiGoZlNYfbUP1S3omJQ6i9CnqADqkSPaOAxwua4/1YWx5CM7oiChJt2Q==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json2module": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", - "integrity": "sha1-APtfSpt638PwZHwpyxe80Zeb6bI=", - "requires": { - "rw": "^1.3.2" - } - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "junk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", - "dev": true - }, - "keyv": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz", - "integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "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 - }, - "known-css-properties": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.21.0.tgz", - "integrity": "sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw==", - "dev": true - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - }, - "leaflet": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", - "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" - }, - "leaflet.markercluster": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.1.tgz", - "integrity": "sha512-dRGndfMZibkWMBD7g8h+lJW0R0keTx1GGMErre7uhqnKiYBoMxR2VPX6Sy8oGNzg+FA7FKtTuO1hGh5HtV9s2g==", - "requires": { - "jshint": "^2.13.1", - "npm-ci": "0.0.2" - } - }, - "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, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lilconfig": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz", - "integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==", - "dev": true - }, - "linebreak": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.0.2.tgz", - "integrity": "sha512-bJwSRsJeAmaZYnkcwl5sCQNfSDAhBuXxb6L27tb+qkBRtUQSSTUa5bcgCPD6hFEkRNlpWHfK7nFMmcANU7ZP1w==", - "requires": { - "base64-js": "0.0.8", - "brfs": "^2.0.2", - "unicode-trie": "^1.0.0" - }, - "dependencies": { - "base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" - }, - "unicode-trie": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-1.0.0.tgz", - "integrity": "sha512-v5raLKsobbFbWLMoX9+bChts/VhPPj3XpkNr/HbqkirXR1DPk8eo9IYKyvk0MQZFkaoRsFj2Rmaqgi2rfAZYtA==", - "requires": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - } - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "requires": { - "uc.micro": "^1.0.1" - } - }, - "lint-staged": { - "version": "10.5.4", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz", - "integrity": "sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "cli-truncate": "^2.1.0", - "commander": "^6.2.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.2.0", - "dedent": "^0.7.0", - "enquirer": "^2.3.6", - "execa": "^4.1.0", - "listr2": "^3.2.2", - "log-symbols": "^4.0.0", - "micromatch": "^4.0.2", - "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "^3.3.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@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" - } - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "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 - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "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, - "requires": { - "@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" - } - }, - "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 - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "listr2": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.4.3.tgz", - "integrity": "sha512-wZmkzNiuinOfwrGqAwTCcPw6aKQGTAMGXwG5xeU1WpDjJNeBA35jGBeWxR3OF+R6Yl5Y3dRG+3vE8t6PDcSNHA==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rxjs": "^6.6.6", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "rxjs": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", - "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - } - } - }, - "lit": { - "version": "2.0.0-rc.2", - "resolved": "https://registry.npmjs.org/lit/-/lit-2.0.0-rc.2.tgz", - "integrity": "sha512-BOCuoJR04WaTV8UqTKk09cNcQA10Aq2LCcBOiHuF7TzWH5RNDsbCBP5QM9sLBSotGTXbDug/gFO08jq6TbyEtw==", - "requires": { - "@lit/reactive-element": "^1.0.0-rc.2", - "lit-element": "^3.0.0-rc.2", - "lit-html": "^2.0.0-rc.3" - } - }, - "lit-element": { - "version": "3.0.0-rc.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0-rc.2.tgz", - "integrity": "sha512-2Z7DabJ3b5K+p5073vFjMODoaWqy5PIaI4y6ADKm+fCGc8OnX9fU9dMoUEBZjFpd/bEFR9PBp050tUtBnT9XTQ==", - "requires": { - "@lit/reactive-element": "^1.0.0-rc.2", - "lit-html": "^2.0.0-rc.3" - } - }, - "lit-html": { - "version": "2.0.0-rc.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0-rc.3.tgz", - "integrity": "sha512-Y6P8LlAyQuqvzq6l/Nc4z5/P5M/rVLYKQIRxcNwSuGajK0g4kbcBFQqZmgvqKG+ak+dHZjfm2HUw9TF5N/pkCw==", - "requires": { - "@types/trusted-types": "^1.0.1" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.capitalize": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", - "dev": true - }, - "lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU=", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", - "dev": true - }, - "lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "dev": true - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "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 - }, - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", - "dev": true - }, - "lodash.topath": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", - "integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", - "dev": true - }, - "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, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "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, - "requires": { - "type-fest": "^0.21.3" - } - }, - "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 - }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "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 - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "longest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha1-eB4YMpaqlPbU2RbcM10NF676I/g=", - "dev": true - }, - "longest-streak": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", - "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", - "dev": true - }, - "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==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "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, - "requires": { - "yallist": "^4.0.0" - } - }, - "magic-string": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz", - "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", - "requires": { - "sourcemap-codec": "^1.4.1" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-obj": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.0.tgz", - "integrity": "sha512-NAq0fCmZYGz9UFEQyndp7sisrow4GroyGeKluyKC/chuITZsPyOyC1UJZPJlVFImhXdROIP5xqouRLThT3BbpQ==", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" - } - } - }, - "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", - "dev": true - }, - "marked-terminal": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", - "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.1", - "cardinal": "^2.1.1", - "chalk": "^4.1.0", - "cli-table3": "^0.6.0", - "node-emoji": "^1.10.0", - "supports-hyperlinks": "^2.1.0" - }, - "dependencies": { - "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, - "requires": { - "type-fest": "^0.21.3" - } - }, - "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 - } - } - }, - "matched": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/matched/-/matched-5.0.1.tgz", - "integrity": "sha512-E1fhSTPRyhAlNaNvGXAgZQlq1hL0bgYMTk/6bktVlIhzUnX/SZs7296ACdVeNJE8xFNGSuvd9IpI7vSnmcqLvw==", - "requires": { - "glob": "^7.1.6", - "picomatch": "^2.2.1" - } - }, - "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 - }, - "mdast-util-from-markdown": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", - "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", - "dev": true, - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-string": "^2.0.0", - "micromark": "~2.11.0", - "parse-entities": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "mdast-util-to-markdown": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", - "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "longest-streak": "^2.0.0", - "mdast-util-to-string": "^2.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.0.0", - "zwitch": "^1.0.0" - } - }, - "mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", - "dev": true - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "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" - } - }, - "merge-source-map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", - "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", - "requires": { - "source-map": "^0.5.6" - } - }, - "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 - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromark": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", - "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", - "dev": true, - "requires": { - "debug": "^4.0.0", - "parse-entities": "^2.0.0" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true - }, - "mime-db": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", - "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" - }, - "mime-types": { - "version": "2.1.28", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", - "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", - "requires": { - "mime-db": "1.45.0" - } - }, - "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 - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "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 - }, - "mini-svg-data-uri": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.2.3.tgz", - "integrity": "sha512-zd6KCAyXgmq6FV1mR10oKXYtvmA9vRoB6xPSTUJTbFApCtkefDnYueVR1gkof3KcdLZo1Y8mjF2DFmQMIxsHNQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "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, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "modern-normalize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz", - "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==", - "dev": true - }, - "modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "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 - }, - "nerf-dart": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", - "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", - "dev": true - }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node-emoji": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", - "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", - "dev": true, - "requires": { - "lodash.toarray": "^4.4.0" - } - }, - "node-fetch": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", - "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", - "dev": true - }, - "normalize-package-data": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", - "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "resolve": "^1.20.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "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 - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-selector": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz", - "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", - "dev": true - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true - }, - "npm": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-7.24.2.tgz", - "integrity": "sha512-120p116CE8VMMZ+hk8IAb1inCPk4Dj3VZw29/n2g6UI77urJKVYb7FZUDW8hY+EBnfsjI/2yrobBgFyzo7YpVQ==", - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "*", - "@npmcli/arborist": "*", - "@npmcli/ci-detect": "*", - "@npmcli/config": "*", - "@npmcli/map-workspaces": "*", - "@npmcli/package-json": "*", - "@npmcli/run-script": "*", - "abbrev": "*", - "ansicolors": "*", - "ansistyles": "*", - "archy": "*", - "cacache": "*", - "chalk": "*", - "chownr": "*", - "cli-columns": "*", - "cli-table3": "*", - "columnify": "*", - "fastest-levenshtein": "*", - "glob": "*", - "graceful-fs": "*", - "hosted-git-info": "*", - "ini": "*", - "init-package-json": "*", - "is-cidr": "*", - "json-parse-even-better-errors": "*", - "libnpmaccess": "*", - "libnpmdiff": "*", - "libnpmexec": "*", - "libnpmfund": "*", - "libnpmhook": "*", - "libnpmorg": "*", - "libnpmpack": "*", - "libnpmpublish": "*", - "libnpmsearch": "*", - "libnpmteam": "*", - "libnpmversion": "*", - "make-fetch-happen": "*", - "minipass": "*", - "minipass-pipeline": "*", - "mkdirp": "*", - "mkdirp-infer-owner": "*", - "ms": "*", - "node-gyp": "*", - "nopt": "*", - "npm-audit-report": "*", - "npm-install-checks": "*", - "npm-package-arg": "*", - "npm-pick-manifest": "*", - "npm-profile": "*", - "npm-registry-fetch": "*", - "npm-user-validate": "*", - "npmlog": "*", - "opener": "*", - "pacote": "*", - "parse-conflict-json": "*", - "qrcode-terminal": "*", - "read": "*", - "read-package-json": "*", - "read-package-json-fast": "*", - "readdir-scoped-modules": "*", - "rimraf": "*", - "semver": "*", - "ssri": "*", - "tar": "*", - "text-table": "*", - "tiny-relative-date": "*", - "treeverse": "*", - "validate-npm-package-name": "*", - "which": "*", - "write-file-atomic": "*" - }, - "dependencies": { - "@gar/promisify": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "@isaacs/string-locale-compare": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "@npmcli/arborist": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^1.0.2", - "@npmcli/metavuln-calculator": "^1.1.0", - "@npmcli/move-file": "^1.1.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^1.0.1", - "@npmcli/package-json": "^1.0.1", - "@npmcli/run-script": "^1.8.2", - "bin-links": "^2.2.1", - "cacache": "^15.0.3", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.1.5", - "npm-pick-manifest": "^6.1.0", - "npm-registry-fetch": "^11.0.0", - "pacote": "^11.3.5", - "parse-conflict-json": "^1.1.1", - "proc-log": "^1.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "ssri": "^8.0.1", - "treeverse": "^1.0.4", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/ci-detect": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "@npmcli/config": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "requires": { - "ini": "^2.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^5.0.0", - "semver": "^7.3.4", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/disparity-colors": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.3.0" - } - }, - "@npmcli/fs": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "@npmcli/git": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - } - }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "@npmcli/map-workspaces": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "read-package-json-fast": "^2.0.1" - } - }, - "@npmcli/metavuln-calculator": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "cacache": "^15.0.5", - "pacote": "^11.1.11", - "semver": "^7.3.2" - } - }, - "@npmcli/move-file": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, - "@npmcli/name-from-folder": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "@npmcli/node-gyp": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "@npmcli/package-json": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1" - } - }, - "@npmcli/promise-spawn": { - "version": "1.3.2", - "bundled": true, - "dev": true, - "requires": { - "infer-owner": "^1.0.4" - } - }, - "@npmcli/run-script": { - "version": "1.8.6", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^7.1.0", - "read-package-json-fast": "^2.0.1" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "bundled": true, - "dev": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "bundled": true, - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "ansistyles": { - "version": "0.1.3", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.6", - "bundled": true, - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "asap": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "asn1": { - "version": "0.2.4", - "bundled": true, - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "bundled": true, - "dev": true - }, - "aws4": { - "version": "1.11.0", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bin-links": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "cmd-shim": "^4.0.1", - "mkdirp": "^1.0.3", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^2.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtins": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "cacache": { - "version": "15.3.0", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - } - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "chalk": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chownr": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "cidr-regex": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "ip-regex": "^4.1.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "cli-columns": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "cli-table3": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "string-width": { - "version": "4.2.2", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "cmd-shim": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "mkdirp-infer-owner": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "color-support": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "colors": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "columnify": { - "version": "1.5.4", - "bundled": true, - "dev": true, - "requires": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - } - }, - "combined-stream": { - "version": "1.0.8", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "common-ancestor-path": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "4.3.2", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true - } - } - }, - "debuglog": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "defaults": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "depd": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "dezalgo": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "bundled": true, - "dev": true - }, - "encoding": { - "version": "0.1.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - } - }, - "env-paths": { - "version": "2.2.1", - "bundled": true, - "dev": true - }, - "err-code": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "extend": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "bundled": true, - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "gauge": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1 || ^2.0.0", - "strip-ansi": "^3.0.1 || ^4.0.0", - "wide-align": "^1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.8", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "bundled": true, - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "hosted-git-info": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "http-proxy-agent": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http-signature": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore-walk": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "ini": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "init-package-json": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "npm-package-arg": "^8.1.5", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "^4.1.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0" - } - }, - "ip": { - "version": "1.1.5", - "bundled": true, - "dev": true - }, - "ip-regex": { - "version": "4.3.0", - "bundled": true, - "dev": true - }, - "is-cidr": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "cidr-regex": "^3.1.1" - } - }, - "is-core-module": { - "version": "2.7.0", - "bundled": true, - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-lambda": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "bundled": true, - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "bundled": true, - "dev": true - }, - "json-stringify-nice": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "bundled": true, - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "just-diff": { - "version": "3.1.1", - "bundled": true, - "dev": true - }, - "just-diff-apply": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "libnpmaccess": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0" - } - }, - "libnpmdiff": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/disparity-colors": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^3.0.4", - "npm-package-arg": "^8.1.4", - "pacote": "^11.3.4", - "tar": "^6.1.0" - } - }, - "libnpmexec": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^2.3.0", - "@npmcli/ci-detect": "^1.3.0", - "@npmcli/run-script": "^1.8.4", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^8.1.2", - "pacote": "^11.3.1", - "proc-log": "^1.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "walk-up-path": "^1.0.0" - } - }, - "libnpmfund": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^2.5.0" - } - }, - "libnpmhook": { - "version": "6.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - } - }, - "libnpmorg": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - } - }, - "libnpmpack": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/run-script": "^1.8.3", - "npm-package-arg": "^8.1.0", - "pacote": "^11.2.6" - } - }, - "libnpmpublish": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "normalize-package-data": "^3.0.2", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^11.0.0", - "semver": "^7.1.3", - "ssri": "^8.0.1" - } - }, - "libnpmsearch": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^11.0.0" - } - }, - "libnpmteam": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^11.0.0" - } - }, - "libnpmversion": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^2.0.7", - "@npmcli/run-script": "^1.8.4", - "json-parse-even-better-errors": "^2.3.1", - "semver": "^7.3.5", - "stringify-package": "^1.0.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-fetch-happen": { - "version": "9.1.0", - "bundled": true, - "dev": true, - "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - } - }, - "mime-db": { - "version": "1.49.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.32", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.49.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minipass": { - "version": "3.1.5", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-fetch": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, - "minipass-flush": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-sized": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "mkdirp-infer-owner": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - } - }, - "ms": { - "version": "2.1.3", - "bundled": true, - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "bundled": true, - "dev": true - }, - "node-gyp": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "nopt": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "npm-audit-report": { - "version": "2.1.5", - "bundled": true, - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "npm-bundled": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-install-checks": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "semver": "^7.1.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npm-package-arg": { - "version": "8.1.5", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" - } - }, - "npm-packlist": { - "version": "2.2.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "6.1.1", - "bundled": true, - "dev": true, - "requires": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - } - }, - "npm-profile": { - "version": "5.0.4", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^11.0.0" - } - }, - "npm-registry-fetch": { - "version": "11.0.0", - "bundled": true, - "dev": true, - "requires": { - "make-fetch-happen": "^9.0.1", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" - } - }, - "npm-user-validate": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npmlog": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - }, - "dependencies": { - "are-we-there-yet": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - } - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "p-map": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "pacote": { - "version": "11.3.5", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.8.2", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^11.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - } - }, - "parse-conflict-json": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "just-diff": "^3.0.1", - "just-diff-apply": "^3.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "proc-log": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "promise-all-reject-late": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-call-limit": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "read": "1" - } - }, - "psl": { - "version": "1.8.0", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "qrcode-terminal": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "qs": { - "version": "6.5.2", - "bundled": true, - "dev": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "read-package-json": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "read-package-json-fast": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "request": { - "version": "2.88.2", - "bundled": true, - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "tough-cookie": { - "version": "2.5.0", - "bundled": true, - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "retry": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.2.1", - "bundled": true, - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true - }, - "semver": { - "version": "7.3.5", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "bundled": true, - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "bundled": true, - "dev": true - }, - "socks": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "ip": "^1.1.5", - "smart-buffer": "^4.1.0" - } - }, - "socks-proxy-agent": { - "version": "6.1.0", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - } - }, - "spdx-correct": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.10", - "bundled": true, - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "bundled": true, - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "8.0.1", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.1.1" - } - }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "stringify-package": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar": { - "version": "6.1.11", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "tiny-relative-date": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "treeverse": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "bundled": true, - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unique-filename": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "uri-js": { - "version": "4.4.1", - "bundled": true, - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.4.0", - "bundled": true, - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtins": "^1.0.3" - } - }, - "verror": { - "version": "1.10.0", - "bundled": true, - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "walk-up-path": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "wcwidth": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "which": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "yallist": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "npm-ci": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/npm-ci/-/npm-ci-0.0.2.tgz", - "integrity": "sha1-n2t2IMKFeAL7baJoEGnkCinjEHI=" - }, - "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, - "requires": { - "path-key": "^3.0.0" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true - }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - } - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "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.3" - } - }, - "orderedmap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.1.tgz", - "integrity": "sha512-3Ux8um0zXbVacKUkcytc0u3HgC0b0bBLT+I60r2J/En72cI0nZffqrA7Xtf2Hqs27j1g82llR5Mhbd0Z1XW4AQ==" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-all": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", - "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", - "dev": true, - "requires": { - "p-map": "^2.0.0" - }, - "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true - }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dev": true, - "requires": { - "p-timeout": "^3.1.0" - } - }, - "p-filter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", - "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", - "dev": true, - "requires": { - "p-map": "^2.0.0" - }, - "dependencies": { - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true - }, - "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, - "requires": { - "p-try": "^2.0.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-reduce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", - "dev": true - }, - "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "requires": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - } - }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "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 - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, - "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, - "requires": { - "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } - } - }, - "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parse-path": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz", - "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", - "dev": true, - "requires": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0", - "qs": "^6.9.4", - "query-string": "^6.13.8" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "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 - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "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 - }, - "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==" - }, - "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 - }, - "pdfkit": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.12.3.tgz", - "integrity": "sha512-+qDLgm2yq6WOKcxTb43lDeo3EtMIDQs0CK1RNqhHC9iT6u0KOmgwAClkYh9xFw2ATbmUZzt4f7KMwDCOfPDluA==", - "requires": { - "crypto-js": "^4.0.0", - "fontkit": "^1.8.1", - "linebreak": "^1.0.2", - "png-js": "^1.0.0" - } - }, - "pdfmake": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.2.tgz", - "integrity": "sha512-e1N+iIIf0LXTvfmf/RaxeqtOKX2qFrNxBbcWmMcg2BUsgcye1bLkdxR7PImmRs8OnqT7qd9XonltZgdTFw8qUA==", - "requires": { - "@foliojs-fork/linebreak": "^1.1.1", - "@foliojs-fork/pdfkit": "^0.12.3", - "iconv-lite": "^0.6.3", - "svg-to-pdfkit": "^0.1.8", - "xmldoc": "^1.1.2" - }, - "dependencies": { - "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==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "png-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", - "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" - }, - "polylabel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/polylabel/-/polylabel-1.1.0.tgz", - "integrity": "sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==", - "requires": { - "tinyqueue": "^2.0.3" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "postcss": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", - "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", - "dev": true, - "requires": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" - } - }, - "postcss-attribute-case-insensitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", - "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^6.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "dev": true, - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-color-functional-notation": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", - "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-color-gray": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", - "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", - "dev": true, - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-color-hex-alpha": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", - "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", - "dev": true, - "requires": { - "postcss": "^7.0.14", - "postcss-values-parser": "^2.0.1" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-color-mod-function": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", - "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", - "dev": true, - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-color-rebeccapurple": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", - "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-custom-media": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", - "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", - "dev": true, - "requires": { - "postcss": "^7.0.14" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-custom-properties": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", - "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", - "dev": true, - "requires": { - "postcss": "^7.0.17", - "postcss-values-parser": "^2.0.1" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-custom-selectors": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", - "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-dir-pseudo-class": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", - "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-double-position-gradients": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", - "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", - "dev": true, - "requires": { - "postcss": "^7.0.5", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-env-function": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", - "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-focus-visible": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", - "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-focus-within": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", - "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-font-variant": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", - "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-gap-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", - "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-html": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", - "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", - "dev": true, - "requires": { - "htmlparser2": "^3.10.0" - } - }, - "postcss-image-set-function": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", - "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-import": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.0.tgz", - "integrity": "sha512-gFDDzXhqr9ELmnLHgCC3TbGfA6Dm/YMb/UN8/f7Uuq4fL7VTk2vOIj6hwINEwbokEmp123bLD7a5m+E+KIetRg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-initial": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz", - "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-js": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", - "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==", - "dev": true, - "requires": { - "camelcase-css": "^2.0.1", - "postcss": "^8.1.6" - } - }, - "postcss-lab-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", - "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", - "dev": true, - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-less": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", - "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", - "dev": true, - "requires": { - "postcss": "^7.0.14" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-load-config": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz", - "integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==", - "dev": true, - "requires": { - "import-cwd": "^3.0.0", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "postcss-logical": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", - "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-media-minmax": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", - "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", - "dev": true - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - } - } - }, - "postcss-nested": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.5.tgz", - "integrity": "sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-nesting": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", - "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-overflow-shorthand": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", - "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-page-break": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", - "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-place": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", - "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-preset-env": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", - "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", - "dev": true, - "requires": { - "autoprefixer": "^9.6.1", - "browserslist": "^4.6.4", - "caniuse-lite": "^1.0.30000981", - "css-blank-pseudo": "^0.1.4", - "css-has-pseudo": "^0.10.0", - "css-prefers-color-scheme": "^3.1.1", - "cssdb": "^4.4.0", - "postcss": "^7.0.17", - "postcss-attribute-case-insensitive": "^4.0.1", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-gray": "^5.0.0", - "postcss-color-hex-alpha": "^5.0.3", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.8", - "postcss-custom-properties": "^8.0.11", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-double-position-gradients": "^1.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" - }, - "dependencies": { - "autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", - "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-pseudo-class-any-link": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", - "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", - "dev": true, - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "postcss-replace-overflow-wrap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", - "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-resolve-nested-selector": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", - "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=", - "dev": true - }, - "postcss-safe-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", - "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", - "dev": true, - "requires": { - "postcss": "^7.0.26" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-sass": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz", - "integrity": "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==", - "dev": true, - "requires": { - "gonzales-pe": "^4.3.0", - "postcss": "^7.0.21" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-scss": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz", - "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==", - "dev": true, - "requires": { - "postcss": "^7.0.6" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-matches": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", - "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-not": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", - "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - } - } - }, - "postcss-syntax": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", - "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", - "dev": true - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "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 - } - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "dev": true, - "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - }, - "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "prettier-plugin-organize-imports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-1.1.1.tgz", - "integrity": "sha512-rFA1lnek1FYkMGthm4xBKME41qUKItTovuo24bCGZu/Vu1n3gW71UPLAkIdwewwkZCe29gRVweSOPXvAdckFuw==", - "dev": true - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true - }, - "printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" - }, - "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==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prosemirror-commands": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.1.4.tgz", - "integrity": "sha512-kj4Qi+8h3EpJtZuuEDwZ9h2/QNGWDsIX/CzjmClxi9GhxWyBUMVUvIFk0mgdqHyX20lLeGmOpc0TLA5aPzgpWg==", - "requires": { - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "prosemirror-dropcursor": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.3.2.tgz", - "integrity": "sha512-4c94OUGyobGnwcQI70OXyMhE/9T4aTgjU+CHxkd5c7D+jH/J0mKM/lk+jneFVKt7+E4/M0D9HzRPifu8U28Thw==", - "requires": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0", - "prosemirror-view": "^1.1.0" - } - }, - "prosemirror-example-setup": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-example-setup/-/prosemirror-example-setup-1.1.2.tgz", - "integrity": "sha512-MTpIMyqk08jFnzxeRMCinCEMtVSTUtxKgQBGxfCbVe9C6zIOqp9qZZJz5Ojaad1GETySyuj8+OIHHvQsIaaaGQ==", - "requires": { - "prosemirror-commands": "^1.0.0", - "prosemirror-dropcursor": "^1.0.0", - "prosemirror-gapcursor": "^1.0.0", - "prosemirror-history": "^1.0.0", - "prosemirror-inputrules": "^1.0.0", - "prosemirror-keymap": "^1.0.0", - "prosemirror-menu": "^1.0.0", - "prosemirror-schema-list": "^1.0.0", - "prosemirror-state": "^1.0.0" - } - }, - "prosemirror-gapcursor": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.1.5.tgz", - "integrity": "sha512-SjbUZq5pgsBDuV3hu8GqgIpZR5eZvGLM+gPQTqjVVYSMUCfKW3EGXTEYaLHEl1bGduwqNC95O3bZflgtAb4L6w==", - "requires": { - "prosemirror-keymap": "^1.0.0", - "prosemirror-model": "^1.0.0", - "prosemirror-state": "^1.0.0", - "prosemirror-view": "^1.0.0" - } - }, - "prosemirror-history": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.1.3.tgz", - "integrity": "sha512-zGDotijea+vnfnyyUGyiy1wfOQhf0B/b6zYcCouBV8yo6JmrE9X23M5q7Nf/nATywEZbgRLG70R4DmfSTC+gfg==", - "requires": { - "prosemirror-state": "^1.2.2", - "prosemirror-transform": "^1.0.0", - "rope-sequence": "^1.3.0" - } - }, - "prosemirror-inputrules": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.1.2.tgz", - "integrity": "sha512-Ja5Z3BWestlHYGvtSGqyvxMeB8QEuBjlHM8YnKtLGUXMDp965qdDV4goV8lJb17kIWHk7e7JNj6Catuoa3302g==", - "requires": { - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "prosemirror-keymap": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.1.4.tgz", - "integrity": "sha512-Al8cVUOnDFL4gcI5IDlG6xbZ0aOD/i3B17VT+1JbHWDguCgt/lBHVTHUBcKvvbSg6+q/W4Nj1Fu6bwZSca3xjg==", - "requires": { - "prosemirror-state": "^1.0.0", - "w3c-keyname": "^2.2.0" - } - }, - "prosemirror-markdown": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.5.1.tgz", - "integrity": "sha512-QvucPHx+gKOQW1SETKUysrful9VBjKqpCFmPotgLfVZ3BdQEGy/NEIFhaXXo3TcuW316MMnKfA90K7GE5I7z8A==", - "requires": { - "markdown-it": "^10.0.0", - "prosemirror-model": "^1.0.0" - } - }, - "prosemirror-menu": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.1.4.tgz", - "integrity": "sha512-2ROsji/X9ciDnVSRvSTqFygI34GEdHfQSsK4zBKjPxSEroeiHHcdRMS1ofNIf2zM0Vpp5/YqfpxynElymQkqzg==", - "requires": { - "crelt": "^1.0.0", - "prosemirror-commands": "^1.0.0", - "prosemirror-history": "^1.0.0", - "prosemirror-state": "^1.0.0" - } - }, - "prosemirror-model": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.11.0.tgz", - "integrity": "sha512-GqoAz/mIYjdv8gVYJ8mWFKpHoTxn/lXq4tXJ6bTVxs+rem2LzMYXrNVXfucGtfsgqsJlRIgng/ByG9j7Q8XDrg==", - "requires": { - "orderedmap": "^1.1.0" - } - }, - "prosemirror-schema-list": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.1.2.tgz", - "integrity": "sha512-dgM9PwtM4twa5WsgSYMB+J8bwjnR43DAD3L9MsR9rKm/nZR5Y85xcjB7gusVMSsbQ2NomMZF03RE6No6mTnclQ==", - "requires": { - "prosemirror-model": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "prosemirror-state": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.3.4.tgz", - "integrity": "sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==", - "requires": { - "prosemirror-model": "^1.0.0", - "prosemirror-transform": "^1.0.0" - } - }, - "prosemirror-transform": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.2.7.tgz", - "integrity": "sha512-/107Lo2zeDgXuJBxb8s/clNu0Z2W8Gv3MKmkuSS/68Mcr7LBaUnN/Hj2g+GUxEJ7MpExCzFs65GrsNo2K9rxUQ==", - "requires": { - "prosemirror-model": "^1.0.0" - } - }, - "prosemirror-view": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.18.1.tgz", - "integrity": "sha512-TZd8byDRfdopLiokBY7T27msCSfWqqRxWs/LnBbdI030F+iI2kS+tO59/XFnpZxMLFKlJgOgGGhM9SzD1Nwdxw==", - "requires": { - "prosemirror-model": "^1.1.0", - "prosemirror-state": "^1.0.0", - "prosemirror-transform": "^1.1.0" - } - }, - "protocols": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", - "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", - "dev": true - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "purgecss": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.0.3.tgz", - "integrity": "sha512-PYOIn5ibRIP34PBU9zohUcCI09c7drPJJtTDAc0Q6QlRz2/CHQ8ywGLdE7ZhxU2VTqB7p5wkvj5Qcm05Rz3Jmw==", - "dev": true, - "requires": { - "commander": "^6.0.0", - "glob": "^7.0.0", - "postcss": "^8.2.1", - "postcss-selector-parser": "^6.0.2" - } - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", - "dev": true - }, - "query-string": { - "version": "6.13.8", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.8.tgz", - "integrity": "sha512-jxJzQI2edQPE/NPUOusNjO/ZOGqr1o2OBa/3M00fU76FsLXDVbJDv/p7ng5OdQyorKrkRz1oqfwmbe5MAMePQg==", - "dev": true, - "requires": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, - "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 - }, - "quote-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", - "integrity": "sha1-hJY/jJwmuULhU/7rU6rnRlK34LI=", - "requires": { - "buffer-equal": "0.0.1", - "minimist": "^1.1.3", - "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "requires": { - "performance-now": "^2.1.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", - "dev": true, - "requires": { - "pify": "^2.3.0" - } - }, - "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, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "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, - "requires": { - "@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" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "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 - } - } - }, - "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, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "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 - } - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "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" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "dev": true, - "requires": { - "esprima": "~4.0.0" - } - }, - "reduce-css-calc": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", - "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==", - "dev": true, - "requires": { - "css-unit-converter": "^1.1.1", - "postcss-value-parser": "^3.3.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", - "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "regression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", - "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=" - }, - "remark": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", - "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", - "dev": true, - "requires": { - "remark-parse": "^9.0.0", - "remark-stringify": "^9.0.0", - "unified": "^9.1.0" - } - }, - "remark-parse": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", - "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", - "dev": true, - "requires": { - "mdast-util-from-markdown": "^0.8.0" - } - }, - "remark-stringify": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz", - "integrity": "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==", - "dev": true, - "requires": { - "mdast-util-to-markdown": "^0.6.0" - } - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "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 - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", - "dev": true, - "requires": { - "global-dirs": "^0.1.1" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "restructure": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-0.5.4.tgz", - "integrity": "sha1-9U591WNZD7NP1r9Vh2EJrsyyjeg=", - "requires": { - "browserify-optional": "^1.0.0" - } - }, - "resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "requires": { - "through": "~2.3.4" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "rgbcolor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", - "integrity": "sha1-1lBezbMEplldom+ktDMHMGd1lF0=" - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.42.4.tgz", - "integrity": "sha512-Zqv3EvNfcllBHyyEUM754npqsZw82VIjK34cDQMwrQ1d6aqxzeYu5yFb7smGkPU4C1Bj7HupIMeT6WU7uIdnMw==", - "requires": { - "fsevents": "~2.3.1" - } - }, - "rollup-plugin-multi-input": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-multi-input/-/rollup-plugin-multi-input-1.2.0.tgz", - "integrity": "sha512-jLmVLYpIB9sFk3JmzwKFryPqZYv1Dib/GzQEy708hfD/xauwgOyKWk7qhKMQp71mbGTuF59neUst/cnveIii+A==", - "dev": true, - "requires": { - "@babel/runtime": "^7.0.0-beta.55", - "core-js": "^3.1.3", - "fast-glob": "^3.0.0", - "lodash": "^4.17.11" - } - }, - "rope-sequence": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.2.tgz", - "integrity": "sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg==" - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true - }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" - }, - "rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", - "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "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==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "requires": { - "xmlchars": "^2.2.0" - } - }, - "scope-analyzer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.1.tgz", - "integrity": "sha512-azEAihtQ9mEyZGhfgTJy3IbOWEzeOrYbg7NcYEshPKnKd+LZmC3TNd5dmDxbLBsTG/JVWmCp+vDJ03vJjeXMHg==", - "requires": { - "array-from": "^2.1.1", - "dash-ast": "^1.0.0", - "es6-map": "^0.1.5", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.1", - "estree-is-function": "^1.0.0", - "get-assigned-identifiers": "^1.1.0" - } - }, - "semantic-release": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-18.0.0.tgz", - "integrity": "sha512-/Szyhq5DTZCYry/aZqpBbK/kqv10ydn6oiiaYOXtPgDbAIkqidZcQOm+mfYFJ0sBTUaOYCKMlcPMgJycP7jDYQ==", - "dev": true, - "requires": { - "@semantic-release/commit-analyzer": "^9.0.0", - "@semantic-release/error": "^3.0.0", - "@semantic-release/github": "^8.0.0", - "@semantic-release/npm": "^8.0.0", - "@semantic-release/release-notes-generator": "^10.0.0", - "aggregate-error": "^3.0.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.0.0", - "env-ci": "^5.0.0", - "execa": "^5.0.0", - "figures": "^3.0.0", - "find-versions": "^4.0.0", - "get-stream": "^6.0.0", - "git-log-parser": "^1.2.0", - "hook-std": "^2.0.0", - "hosted-git-info": "^4.0.0", - "lodash": "^4.17.21", - "marked": "^2.0.0", - "marked-terminal": "^4.1.1", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "p-reduce": "^2.0.0", - "read-pkg-up": "^7.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.3.2", - "semver-diff": "^3.1.1", - "signale": "^1.2.1", - "yargs": "^16.2.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "requires": { - "@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" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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 - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "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 - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "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, - "requires": { - "@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" - } - }, - "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 - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, - "semver-regex": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz", - "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" - }, - "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, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "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 - }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "signale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", - "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", - "dev": true, - "requires": { - "chalk": "^2.3.2", - "figures": "^2.0.0", - "pkg-conf": "^2.1.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "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, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "spawn-error-forwarder": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", - "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "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, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "specificity": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz", - "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==", - "dev": true - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "requires": { - "readable-stream": "^3.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "ssf": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", - "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "requires": { - "frac": "~1.1.2" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "stackblur-canvas": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz", - "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==" - }, - "static-eval": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.0.tgz", - "integrity": "sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw==", - "requires": { - "escodegen": "^1.11.1" - }, - "dependencies": { - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "static-module": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/static-module/-/static-module-3.0.4.tgz", - "integrity": "sha512-gb0v0rrgpBkifXCa3yZXxqVmXDVE+ETXj6YlC/jt5VzOnGXR2C15+++eXuMDUYsePnbhf+lwW0pE1UXyOLtGCw==", - "requires": { - "acorn-node": "^1.3.0", - "concat-stream": "~1.6.0", - "convert-source-map": "^1.5.1", - "duplexer2": "~0.1.4", - "escodegen": "^1.11.1", - "has": "^1.0.1", - "magic-string": "0.25.1", - "merge-source-map": "1.0.4", - "object-inspect": "^1.6.0", - "readable-stream": "~2.3.3", - "scope-analyzer": "^2.0.1", - "shallow-copy": "~0.0.1", - "static-eval": "^2.0.5", - "through2": "~2.0.3" - }, - "dependencies": { - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", - "dev": true - }, - "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==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string.prototype.trim": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", - "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "dependencies": { - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "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 - }, - "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 - }, - "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, - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true - }, - "style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=", - "dev": true - }, - "stylehacks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.0.tgz", - "integrity": "sha1-ZLMjlRxKJOX8ey7AbBN78y0VXoo=", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^6.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "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 - } - } - }, - "stylelint": { - "version": "13.13.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.13.1.tgz", - "integrity": "sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ==", - "dev": true, - "requires": { - "@stylelint/postcss-css-in-js": "^0.37.2", - "@stylelint/postcss-markdown": "^0.36.2", - "autoprefixer": "^9.8.6", - "balanced-match": "^2.0.0", - "chalk": "^4.1.1", - "cosmiconfig": "^7.0.0", - "debug": "^4.3.1", - "execall": "^2.0.0", - "fast-glob": "^3.2.5", - "fastest-levenshtein": "^1.0.12", - "file-entry-cache": "^6.0.1", - "get-stdin": "^8.0.0", - "global-modules": "^2.0.0", - "globby": "^11.0.3", - "globjoin": "^0.1.4", - "html-tags": "^3.1.0", - "ignore": "^5.1.8", - "import-lazy": "^4.0.0", - "imurmurhash": "^0.1.4", - "known-css-properties": "^0.21.0", - "lodash": "^4.17.21", - "log-symbols": "^4.1.0", - "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", - "micromatch": "^4.0.4", - "normalize-selector": "^0.2.0", - "postcss": "^7.0.35", - "postcss-html": "^0.36.0", - "postcss-less": "^3.1.4", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^4.0.2", - "postcss-sass": "^0.4.4", - "postcss-scss": "^2.1.1", - "postcss-selector-parser": "^6.0.5", - "postcss-syntax": "^0.36.2", - "postcss-value-parser": "^4.1.0", - "resolve-from": "^5.0.0", - "slash": "^3.0.0", - "specificity": "^0.4.1", - "string-width": "^4.2.2", - "strip-ansi": "^6.0.0", - "style-search": "^0.1.0", - "sugarss": "^2.0.0", - "svg-tags": "^1.0.0", - "table": "^6.6.0", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^3.0.3" - }, - "dependencies": { - "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 - }, - "autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", - "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", - "dev": true, - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - } - }, - "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 - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@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" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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, - "requires": { - "global-prefix": "^3.0.0" - } - }, - "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, - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - } - }, - "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "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 - }, - "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 - }, - "meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "dev": true, - "requires": { - "@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" - } - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "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, - "requires": { - "@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" - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - } - } - }, - "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 - }, - "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 - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "stylelint-config-recommended": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-4.0.0.tgz", - "integrity": "sha512-sgna89Ng+25Hr9kmmaIxpGWt2LStVm1xf1807PdcWasiPDaOTkOHRL61sINw0twky7QMzafCGToGDnHT/kTHtQ==", - "dev": true - }, - "stylelint-config-standard": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-21.0.0.tgz", - "integrity": "sha512-Yf6mx5oYEbQQJxWuW7X3t1gcxqbUx52qC9SMS3saC2ruOVYEyqmr5zSW6k3wXflDjjFrPhar3kp68ugRopmlzg==", - "dev": true, - "requires": { - "stylelint-config-recommended": "^4.0.0" - } - }, - "sugarss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", - "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==", - "dev": true, - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.36", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", - "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - } - }, - "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 - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", - "dev": true - }, - "svg-to-pdfkit": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/svg-to-pdfkit/-/svg-to-pdfkit-0.1.8.tgz", - "integrity": "sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==", - "requires": { - "pdfkit": ">=0.8.1" - } - }, - "svgo": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.3.1.tgz", - "integrity": "sha512-riDDIQgXpEnn0BEl9Gvhh1LNLIyiusSpt64IR8upJu7MwxnzetmF/Y57pXQD2NMX2lVyMRzXt5f2M5rO4wG7Dw==", - "dev": true, - "requires": { - "@trysound/sax": "0.1.1", - "chalk": "^4.1.0", - "commander": "^7.1.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.2", - "csso": "^4.2.0", - "stable": "^0.1.8" - }, - "dependencies": { - "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 - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-tree": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz", - "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", - "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", - "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "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 - } - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, - "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==" - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "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 - }, - "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 - }, - "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 - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "tailwindcss": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.4.tgz", - "integrity": "sha512-OdBCPgazNNsknSP+JfrPzkay9aqKjhKtFhbhgxHgvEFdHy/GuRPo2SCJ4w1SFTN8H6FPI4m6qD/Jj20NWY1GkA==", - "dev": true, - "requires": { - "@fullhuman/postcss-purgecss": "^4.0.3", - "arg": "^5.0.0", - "bytes": "^3.0.0", - "chalk": "^4.1.1", - "chokidar": "^3.5.2", - "color": "^3.1.3", - "cosmiconfig": "^7.0.0", - "detective": "^5.2.0", - "didyoumean": "^1.2.1", - "dlv": "^1.1.3", - "fast-glob": "^3.2.5", - "fs-extra": "^10.0.0", - "glob-parent": "^6.0.0", - "html-tags": "^3.1.0", - "is-glob": "^4.0.1", - "lodash": "^4.17.21", - "lodash.topath": "^4.5.2", - "modern-normalize": "^1.1.0", - "node-emoji": "^1.8.1", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss-js": "^3.0.3", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.5", - "postcss-selector-parser": "^6.0.6", - "postcss-value-parser": "^4.1.0", - "pretty-hrtime": "^1.0.3", - "quick-lru": "^5.1.1", - "reduce-css-calc": "^2.1.8", - "resolve": "^1.20.0", - "tmp": "^0.2.1" - }, - "dependencies": { - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@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" - } - }, - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "glob-parent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.0.tgz", - "integrity": "sha512-Hdd4287VEJcZXUwv1l8a+vXC1GjOQqXe+VS30w/ypihpcnu9M1n3xeYeJu5CBpeEQj2nAab2xxz28GuA3vp4Ww==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "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, - "requires": { - "@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" - } - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "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 - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "tape": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.13.3.tgz", - "integrity": "sha512-0/Y20PwRIUkQcTCSi4AASs+OANZZwqPKaipGCEwp10dQMipVvSZwUUCi01Y/OklIGyHKFhIcjock+DKnBfLAFw==", - "requires": { - "deep-equal": "~1.1.1", - "defined": "~1.0.0", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "function-bind": "~1.1.1", - "glob": "~7.1.6", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.0.5", - "minimist": "~1.2.5", - "object-inspect": "~1.7.0", - "resolve": "~1.17.0", - "resumer": "~0.0.0", - "string.prototype.trim": "~1.2.1", - "through": "~2.3.8" - }, - "dependencies": { - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "requires": { - "has": "^1.0.3" - } - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" - } - } - }, - "temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true - }, - "tempy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", - "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", - "dev": true, - "requires": { - "del": "^6.0.0", - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "dependencies": { - "type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true - } - } - }, - "text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "requires": { - "readable-stream": "3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" - }, - "tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "requires": { - "punycode": "^2.1.1" - } - }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", - "dev": true - }, - "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 - }, - "trim-off-newlines": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz", - "integrity": "sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg==", - "dev": true - }, - "trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", - "dev": true - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "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, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "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 - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", - "dev": true - }, - "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==" - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true - }, - "unbox-primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", - "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.0", - "has-symbols": "^1.0.0", - "which-boxed-primitive": "^1.0.1" - } - }, - "unicode-properties": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.3.1.tgz", - "integrity": "sha512-nIV3Tf3LcUEZttY/2g4ZJtGXhWwSkuLL+rCu0DIAMbjyVPj+8j5gNVz4T/sVbnQybIsd5SFGkPKg/756OY6jlA==", - "requires": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "requires": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "unified": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz", - "integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==", - "dev": true, - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - } - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "unist-util-find-all-after": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz", - "integrity": "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==", - "dev": true, - "requires": { - "unist-util-is": "^4.0.0" - } - }, - "unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", - "dev": true - }, - "unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dev": true, - "requires": { - "@types/unist": "^2.0.2" - } - }, - "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "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, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "dev": true - }, - "venn.js": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", - "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", - "requires": { - "d3-selection": "^1.0.2", - "d3-transition": "^1.0.1", - "fmin": "0.0.2" - } - }, - "vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - } - } - }, - "vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "vite": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.3.8.tgz", - "integrity": "sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==", - "dev": true, - "requires": { - "esbuild": "^0.12.8", - "fsevents": "~2.3.2", - "postcss": "^8.3.4", - "resolve": "^1.20.0", - "rollup": "^2.38.5" - }, - "dependencies": { - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - } - } - }, - "vite-plugin-ruby": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vite-plugin-ruby/-/vite-plugin-ruby-2.0.4.tgz", - "integrity": "sha512-1YawT1DKSbY/N8OveNvhNuUOnXNgilMY38SzgLgTEIjIbauyvbArjKii3eK3JzmUcjr0rsPtKin7Omszhc/kvA==", - "dev": true, - "requires": { - "debug": "^4.3.1", - "fast-glob": "^3.2.4" - } - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-keyname": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", - "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "requires": { - "xml-name-validator": "^3.0.0" - } - }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" - }, - "wmf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", - "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==" - }, - "word": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/word/-/word-0.4.0.tgz", - "integrity": "sha512-Aq84KjS7Z9HSU14qf4l/NEouaqfJAZtE9zEz7TIvw9V/3oJeUbjQwhz7ggqbL7I7REt4Bz+9HuCWsBO5N7xChw==", - "requires": { - "cfb": "^1.2.0", - "jsdom": "^16.2.2" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - }, - "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, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "requires": {} - }, - "xlsx": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.17.2.tgz", - "integrity": "sha512-RIhN6/oc/ZqYZqY4jz4AX92yNfULhtNrcZP1lknIcsyR+Ra8Zu/9F1lAZWncYbDex95iYQX/XNNNzNFXZjlNOQ==", - "requires": { - "adler-32": "~1.2.0", - "cfb": "^1.1.4", - "codepage": "~1.15.0", - "commander": "~2.17.1", - "crc-32": "~1.2.0", - "exit-on-epipe": "~1.0.1", - "fflate": "^0.3.8", - "ssf": "~0.11.2", - "wmf": "~1.0.1", - "word": "~0.4.0" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - } - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "xmldoc": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-1.1.2.tgz", - "integrity": "sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ==", - "requires": { - "sax": "^1.2.1" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "dependencies": { - "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 - }, - "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 - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", - "dev": true - }, - "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 - }, - "zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", - "dev": true - } - } -} diff --git a/package.json b/package.json index 34d62ace..3b51642c 100644 --- a/package.json +++ b/package.json @@ -1,94 +1,121 @@ { - "name": "castopod-host", - "version": "1.0.0-alpha.80", + "name": "castopod", + "version": "2.0.0-next.3", "description": "Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.", "private": true, "license": "AGPL-3.0-or-later", + "type": "module", "repository": { "type": "git", - "url": "https://code.podlibre.org/podlibre/castopod-host.git" + "url": "https://code.castopod.org/adaures/castopod.git" }, "scripts": { "dev": "vite", "build": "tsc && vite build", "serve": "vite preview", - "build:static": "npm run build:icons && npm run build:svg && npm run copy:images", - "build:icons": "svgo -f app/Resources/icons -o public/assets/icons -r --config=./.svgo.icons.js", - "build:svg": "svgo -f app/Resources/images -o public/assets/images -r --config=./.svgo.js", - "copy:images": "cpy app/Resources/images/*.jpg public/assets/images", - "lint": "eslint --ext js,ts app/Resources", - "lint:fix": "eslint --ext js,ts app/Resources --fix", - "lint:css": "stylelint \"app/Resources/**/*.css\"", - "lint:css:fix": "stylelint --fix \"app/Resources/**/*.css\"", - "prettier": "prettier --check --ignore-path .gitignore .", - "prettier:fix": "prettier --write --ignore-path .gitignore .", + "build:static": "pnpm run build:icons && pnpm run build:svg", + "build:icons": "svgo -f resources/icons -o resources/icons -r --config=./.svgo.icons.cjs", + "build:svg": "svgo -f resources/static/images -o resources/static/images -r --config=./.svgo.cjs", + "lint": "eslint", + "lint:fix": "eslint --fix", + "lint:css": "stylelint -f verbose \"resources/**/*.css\"", + "lint:css:fix": "stylelint -f verbose --fix \"resources/**/*.css\"", + "prettier": "prettier --check . --ignore-path ./.gitignore --ignore-path ./docs/.gitignore", + "format": "prettier --write . --ignore-path ./.gitignore --ignore-path ./docs/.gitignore", "typecheck": "tsc", - "commit": "git-cz", + "all-contributors:add": "all-contributors add", + "all-contributors:generate": "all-contributors generate", + "commit": "cz", "release": "semantic-release", - "prepare": "is-ci || husky install" + "prepare": "is-ci || husky" }, "dependencies": { - "@amcharts/amcharts4": "^4.10.17", - "@amcharts/amcharts4-geodata": "^4.1.19", - "@popperjs/core": "^2.9.1", - "@rollup/plugin-multi-entry": "^4.0.0", - "choices.js": "^9.0.1", - "flatpickr": "^4.6.9", - "leaflet": "^1.7.1", - "leaflet.markercluster": "^1.5.1", - "lit": "^2.0.0-rc.2", - "prosemirror-example-setup": "^1.1.2", - "prosemirror-markdown": "^1.5.1", - "prosemirror-state": "^1.3.4", - "prosemirror-view": "^1.18.1" + "@amcharts/amcharts4": "^4.10.40", + "@amcharts/amcharts4-geodata": "^4.1.31", + "@codemirror/commands": "^6.10.2", + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-xml": "^6.1.0", + "@codemirror/language": "^6.12.1", + "@codemirror/state": "^6.5.4", + "@codemirror/view": "^6.39.14", + "@floating-ui/dom": "^1.7.5", + "@github/clipboard-copy-element": "^1.3.0", + "@github/hotkey": "^3.1.1", + "@github/markdown-toolbar-element": "^2.2.3", + "@github/relative-time-element": "^5.0.0", + "@patternfly/elements": "^4.3.1", + "@vime/core": "^5.4.1", + "choices.js": "^11.1.0", + "codemirror": "^6.0.2", + "flatpickr": "^4.6.13", + "htmlfy": "^1.0.1", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "lit": "^3.3.2", + "marked": "^17.0.3", + "wavesurfer.js": "^7.12.1", + "xml-formatter": "^3.6.7" }, "devDependencies": { - "@commitlint/cli": "^12.0.1", - "@commitlint/config-conventional": "^12.0.1", - "@semantic-release/changelog": "^6.0.1", - "@semantic-release/exec": "^6.0.2", + "@commitlint/cli": "^20.4.2", + "@commitlint/config-conventional": "^20.4.2", + "@csstools/css-tokenizer": "^4.0.0", + "@eslint/eslintrc": "^3.3.3", + "@eslint/js": "^10.0.1", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", - "@semantic-release/gitlab": "^7.0.4", - "@tailwindcss/forms": "^0.2.1", - "@tailwindcss/line-clamp": "^0.2.0", - "@tailwindcss/typography": "^0.4.0", - "@types/leaflet": "^1.7.5", - "@types/prosemirror-markdown": "^1.5.1", - "@types/prosemirror-view": "^1.17.1", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "cpy-cli": "^3.1.1", - "cross-env": "^7.0.3", - "cssnano": "^4.1.10", + "@semantic-release/gitlab": "^13.3.0", + "@tailwindcss/forms": "^0.5.11", + "@tailwindcss/typography": "^0.5.19", + "@types/leaflet": "^1.9.21", + "all-contributors-cli": "^6.26.1", + "commitizen": "^4.3.1", + "conventional-changelog-conventionalcommits": "^9.1.0", + "cross-env": "^10.1.0", + "cssnano": "^7.1.2", "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.22.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-prettier": "^3.3.1", - "husky": "^6.0.0", - "is-ci": "^3.0.0", - "lint-staged": "^10.5.4", - "postcss-import": "^14.0.0", - "postcss-preset-env": "^6.7.0", - "prettier": "2.2.1", - "prettier-plugin-organize-imports": "^1.1.1", - "rollup-plugin-multi-input": "^1.2.0", - "semantic-release": "^18.0.0", - "stylelint": "^13.12.0", - "stylelint-config-standard": "^21.0.0", - "svgo": "^2.2.2", - "tailwindcss": "^2.2.4", - "typescript": "^4.2.3", - "vite": "^2.3.8", - "vite-plugin-ruby": "^2.0.4" + "eslint": "^10.0.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.5", + "glob": "^13.0.5", + "globals": "^17.3.0", + "husky": "^9.1.7", + "is-ci": "^4.1.0", + "lint-staged": "^16.2.7", + "postcss": "^8.5.6", + "postcss-import": "^16.1.1", + "postcss-nesting": "^14.0.0", + "postcss-preset-env": "^11.1.3", + "postcss-reporter": "^7.1.0", + "prettier": "3.8.1", + "prettier-plugin-organize-imports": "^4.3.0", + "semantic-release": "^25.0.3", + "sharp": "^0.34.5", + "stylelint": "^17.3.0", + "stylelint-config-standard": "^40.0.0", + "svgo": "^4.0.0", + "tailwindcss": "^3.4.19", + "typescript": "~5.9.3", + "typescript-eslint": "^8.56.0", + "vite": "^7.3.1", + "vite-plugin-codeigniter": "^2.0.0", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-pwa": "^1.2.0", + "vite-plugin-static-copy": "^3.2.0", + "workbox-build": "^7.4.0", + "workbox-core": "^7.4.0", + "workbox-routing": "^7.4.0", + "workbox-strategies": "^7.4.0" }, "lint-staged": { "*.{js,ts,css,md,json}": "prettier --write", - "*.{ts,js}": "eslint --ext js,ts,tsx app/Resources --fix", + "*.{ts,js}": "eslint --fix", "*.css": "stylelint --fix" }, "config": { "commitizen": { - "path": "./node_modules/cz-conventional-changelog" + "path": "cz-conventional-changelog" } } } diff --git a/php-icons.php b/php-icons.php new file mode 100644 index 00000000..afcb4588 --- /dev/null +++ b/php-icons.php @@ -0,0 +1,21 @@ +withPaths([__DIR__ . '/app', __DIR__ . '/themes', __DIR__ . '/resources']) + ->withLocalIconSets([ + 'funding' => __DIR__ . '/resources/icons/funding', + 'podcasting' => __DIR__ . '/resources/icons/podcasting', + 'social' => __DIR__ . '/resources/icons/social', + 'custom' => __DIR__ . '/resources/icons/custom', + ]) + ->withDefaultIconPerSet([ + 'funding' => 'funding:default', + 'podcasting' => 'podcasting:default', + 'social' => 'social:default', + ]) + ->withDefaultPrefix('ri') + ->withPlaceholder('�'); diff --git a/phpstan.neon b/phpstan.neon index 293671ea..37bf9c76 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,34 +3,51 @@ parameters: level: 6 paths: - app + - modules - tests bootstrapFiles: - - vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php + - vendor/codeigniter4/framework/system/Test/bootstrap.php scanDirectories: - - app/Helpers - - vendor/codeigniter4/codeigniter4/system/Helpers - - vendor/myth/auth/src/Helpers - excludes_analyse: - - app/Config/Routes.php + - app + - modules + - vendor/codeigniter4 + excludePaths: - app/Libraries/Router.php - - app/Libraries/ActivityPub/Config/Routes.php - - app/Libraries/Analytics/Config/Routes.php - app/Views/* + - modules/*/Views/* + - themes/* + codeigniter: + additionalConfigNamespaces: + - Modules\Admin\Config\ + - Modules\Analytics\Config\ + - Modules\Api\Rest\V1\Config\ + - Modules\Auth\Config\ + - Modules\Fediverse\Config\ + - Modules\Install\Config\ + - Modules\Media\Config\ + - Modules\MediaClipper\Config\ + - Modules\Plugins\Config\ + - Modules\PodcastImport\Config\ + - Modules\PremiumPodcasts\Config\ + - Modules\WebSub\Config\ + - ViewThemes\Config\ + - Vite\Config\ + additionalModelNamespaces: + - Modules\Analytics\Models\ + - Modules\Auth\Models\ + - Modules\Fediverse\Models\ + - Modules\Media\Models\ + - Modules\PremiumPodcasts\Models\ + - CodeIgniter\Shield\Models\ + additionalServices: + - CodeIgniter\Settings\Config\Services + - CodeIgniter\Shield\Config\Services + - Michalsn\Uuid\Config\Services + - Modules\Media\Config\Services + - Modules\Platforms\Config\Services + - Modules\Plugins\Config\Services + - Modules\PremiumPodcasts\Config\Services + - Modules\Api\Rest\V1\Config\Services ignoreErrors: - - '#This property type might be inlined to PHP. Do you have confidence it is correct\? Put it here#' - - '#^Cognitive complexity for#' - - '#^Class cognitive complexity is#' - - '#Do not use chained method calls. Put each on separated lines.#' - - '#Do not inherit from abstract class, better use composition#' - - '#Cannot access property [\$a-z_]+ on ((array\|)?object)#' - - '#^Call to an undefined method CodeIgniter\\Database\\BaseBuilder#' - - '#^Call to an undefined method CodeIgniter\\Database\\ConnectionInterface#' - - '#Access to an undefined property CodeIgniter\\Database\\BaseBuilder::\$pager#' - - '#Function \"preg_.*\(\)\" cannot be used/left in the code#' - - '#Function "property_exists\(\)" cannot be used/left in the code#' - - - message: '#Function "function_exists\(\)" cannot be used/left in the code#' - paths: - - app/Helpers - - app/Libraries/ActivityPub/Helpers - - app/Libraries/Analytics/Helpers + - identifier: missingType.generics + - '#\$callback of static method CodeIgniter\\Events\\Events\:\:on\(\) expects callable\(mixed\)\: mixed, Closure\(mixed, mixed\)\: void given.#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 80405026..766a18f5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,57 +1,66 @@ - - - - - ./app - - - ./app/Views - ./app/Config/Routes.php - - - - - - - - - - - ./tests - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + ./tests + + + + + + + + + + ./app + + + ./app/Views + ./app/Config/Routes.php + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/.gitkeep b/plugins/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..6e2c7420 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,16208 @@ +lockfileVersion: "9.0" + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + "@amcharts/amcharts4": + specifier: ^4.10.40 + version: 4.10.40 + "@amcharts/amcharts4-geodata": + specifier: ^4.1.31 + version: 4.1.31 + "@codemirror/commands": + specifier: ^6.10.2 + version: 6.10.2 + "@codemirror/lang-html": + specifier: ^6.4.11 + version: 6.4.11 + "@codemirror/lang-xml": + specifier: ^6.1.0 + version: 6.1.0 + "@codemirror/language": + specifier: ^6.12.1 + version: 6.12.1 + "@codemirror/state": + specifier: ^6.5.4 + version: 6.5.4 + "@codemirror/view": + specifier: ^6.39.14 + version: 6.39.14 + "@floating-ui/dom": + specifier: ^1.7.5 + version: 1.7.5 + "@github/clipboard-copy-element": + specifier: ^1.3.0 + version: 1.3.0 + "@github/hotkey": + specifier: ^3.1.1 + version: 3.1.1 + "@github/markdown-toolbar-element": + specifier: ^2.2.3 + version: 2.2.3 + "@github/relative-time-element": + specifier: ^5.0.0 + version: 5.0.0 + "@patternfly/elements": + specifier: ^4.3.1 + version: 4.3.1 + "@vime/core": + specifier: ^5.4.1 + version: 5.4.1 + choices.js: + specifier: ^11.1.0 + version: 11.1.0 + codemirror: + specifier: ^6.0.2 + version: 6.0.2 + flatpickr: + specifier: ^4.6.13 + version: 4.6.13 + htmlfy: + specifier: ^1.0.1 + version: 1.0.1 + leaflet: + specifier: ^1.9.4 + version: 1.9.4 + leaflet.markercluster: + specifier: ^1.5.3 + version: 1.5.3(leaflet@1.9.4) + lit: + specifier: ^3.3.2 + version: 3.3.2 + marked: + specifier: ^17.0.3 + version: 17.0.3 + wavesurfer.js: + specifier: ^7.12.1 + version: 7.12.1 + xml-formatter: + specifier: ^3.6.7 + version: 3.6.7 + devDependencies: + "@commitlint/cli": + specifier: ^20.4.2 + version: 20.4.2(@types/node@24.7.0)(typescript@5.9.3) + "@commitlint/config-conventional": + specifier: ^20.4.2 + version: 20.4.2 + "@csstools/css-tokenizer": + specifier: ^4.0.0 + version: 4.0.0 + "@eslint/eslintrc": + specifier: ^3.3.3 + version: 3.3.3 + "@eslint/js": + specifier: ^10.0.1 + version: 10.0.1(eslint@10.0.0(jiti@1.21.7)) + "@semantic-release/changelog": + specifier: ^6.0.3 + version: 6.0.3(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/exec": + specifier: ^7.1.0 + version: 7.1.0(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/git": + specifier: ^10.0.1 + version: 10.0.1(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/gitlab": + specifier: ^13.3.0 + version: 13.3.0(semantic-release@25.0.3(typescript@5.9.3)) + "@tailwindcss/forms": + specifier: ^0.5.11 + version: 0.5.11(tailwindcss@3.4.19(yaml@2.8.2)) + "@tailwindcss/typography": + specifier: ^0.5.19 + version: 0.5.19(tailwindcss@3.4.19(yaml@2.8.2)) + "@types/leaflet": + specifier: ^1.9.21 + version: 1.9.21 + all-contributors-cli: + specifier: ^6.26.1 + version: 6.26.1 + commitizen: + specifier: ^4.3.1 + version: 4.3.1(@types/node@24.7.0)(typescript@5.9.3) + conventional-changelog-conventionalcommits: + specifier: ^9.1.0 + version: 9.1.0 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 + cssnano: + specifier: ^7.1.2 + version: 7.1.2(postcss@8.5.6) + cz-conventional-changelog: + specifier: ^3.3.0 + version: 3.3.0(@types/node@24.7.0)(typescript@5.9.3) + eslint: + specifier: ^10.0.0 + version: 10.0.0(jiti@1.21.7) + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@10.0.0(jiti@1.21.7)) + eslint-plugin-prettier: + specifier: ^5.5.5 + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.0(jiti@1.21.7)))(eslint@10.0.0(jiti@1.21.7))(prettier@3.8.1) + glob: + specifier: ^13.0.5 + version: 13.0.5 + globals: + specifier: ^17.3.0 + version: 17.3.0 + husky: + specifier: ^9.1.7 + version: 9.1.7 + is-ci: + specifier: ^4.1.0 + version: 4.1.0 + lint-staged: + specifier: ^16.2.7 + version: 16.2.7 + postcss: + specifier: ^8.5.6 + version: 8.5.6 + postcss-import: + specifier: ^16.1.1 + version: 16.1.1(postcss@8.5.6) + postcss-nesting: + specifier: ^14.0.0 + version: 14.0.0(postcss@8.5.6) + postcss-preset-env: + specifier: ^11.1.3 + version: 11.1.3(postcss@8.5.6) + postcss-reporter: + specifier: ^7.1.0 + version: 7.1.0(postcss@8.5.6) + prettier: + specifier: 3.8.1 + version: 3.8.1 + prettier-plugin-organize-imports: + specifier: ^4.3.0 + version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + semantic-release: + specifier: ^25.0.3 + version: 25.0.3(typescript@5.9.3) + sharp: + specifier: ^0.34.5 + version: 0.34.5 + stylelint: + specifier: ^17.3.0 + version: 17.3.0(typescript@5.9.3) + stylelint-config-standard: + specifier: ^40.0.0 + version: 40.0.0(stylelint@17.3.0(typescript@5.9.3)) + svgo: + specifier: ^4.0.0 + version: 4.0.0 + tailwindcss: + specifier: ^3.4.19 + version: 3.4.19(yaml@2.8.2) + typescript: + specifier: ~5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.56.0 + version: 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + vite-plugin-codeigniter: + specifier: ^2.0.0 + version: 2.0.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-inspect: + specifier: ^11.3.3 + version: 11.3.3(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + vite-plugin-pwa: + specifier: ^1.2.0 + version: 1.2.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2))(workbox-build@7.4.0)(workbox-window@7.4.0) + vite-plugin-static-copy: + specifier: ^3.2.0 + version: 3.2.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + workbox-build: + specifier: ^7.4.0 + version: 7.4.0 + workbox-core: + specifier: ^7.4.0 + version: 7.4.0 + workbox-routing: + specifier: ^7.4.0 + version: 7.4.0 + workbox-strategies: + specifier: ^7.4.0 + version: 7.4.0 + +packages: + "@actions/core@3.0.0": + resolution: + { + integrity: sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==, + } + + "@actions/exec@3.0.0": + resolution: + { + integrity: sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==, + } + + "@actions/http-client@4.0.0": + resolution: + { + integrity: sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==, + } + + "@actions/io@3.0.2": + resolution: + { + integrity: sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==, + } + + "@alloc/quick-lru@5.2.0": + resolution: + { + integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, + } + engines: { node: ">=10" } + + "@amcharts/amcharts4-geodata@4.1.31": + resolution: + { + integrity: sha512-ciX2rOX6YZaRv/GGXqQNjV4ixhe1Ke9r+4xlwm9YuUHZ5QZSfLx6obXRqhmQeTdnNcxjveMoZ//E7xfotvqgVg==, + } + + "@amcharts/amcharts4@4.10.40": + resolution: + { + integrity: sha512-F5RrlWCg/fIRvTnnXenWZg7bTlEWJDvELyvXVAAi5GFvFVF4IegIP1vk5TatkgBzYO5v+SNGj2S3N1MkLwYA8w==, + } + + "@apideck/better-ajv-errors@0.3.6": + resolution: + { + integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==, + } + engines: { node: ">=10" } + peerDependencies: + ajv: ">=8" + + "@babel/code-frame@7.29.0": + resolution: + { + integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==, + } + engines: { node: ">=6.9.0" } + + "@babel/compat-data@7.29.0": + resolution: + { + integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==, + } + engines: { node: ">=6.9.0" } + + "@babel/core@7.29.0": + resolution: + { + integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==, + } + engines: { node: ">=6.9.0" } + + "@babel/generator@7.29.1": + resolution: + { + integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-annotate-as-pure@7.27.3": + resolution: + { + integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-compilation-targets@7.28.6": + resolution: + { + integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-create-class-features-plugin@7.28.6": + resolution: + { + integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-create-regexp-features-plugin@7.28.5": + resolution: + { + integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-define-polyfill-provider@0.6.6": + resolution: + { + integrity: sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==, + } + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + + "@babel/helper-globals@7.28.0": + resolution: + { + integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-member-expression-to-functions@7.28.5": + resolution: + { + integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-imports@7.28.6": + resolution: + { + integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-transforms@7.28.6": + resolution: + { + integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-optimise-call-expression@7.27.1": + resolution: + { + integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-plugin-utils@7.28.6": + resolution: + { + integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-remap-async-to-generator@7.27.1": + resolution: + { + integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-replace-supers@7.28.6": + resolution: + { + integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-skip-transparent-expression-wrappers@7.27.1": + resolution: + { + integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-string-parser@7.27.1": + resolution: + { + integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-identifier@7.28.5": + resolution: + { + integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-option@7.27.1": + resolution: + { + integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-wrap-function@7.28.6": + resolution: + { + integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/helpers@7.28.6": + resolution: + { + integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==, + } + engines: { node: ">=6.9.0" } + + "@babel/parser@7.29.0": + resolution: + { + integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5": + resolution: + { + integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1": + resolution: + { + integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1": + resolution: + { + integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1": + resolution: + { + integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.13.0 + + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6": + resolution: + { + integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + resolution: + { + integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-import-assertions@7.28.6": + resolution: + { + integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-import-attributes@7.28.6": + resolution: + { + integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-unicode-sets-regex@7.18.6": + resolution: + { + integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-transform-arrow-functions@7.27.1": + resolution: + { + integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-async-generator-functions@7.29.0": + resolution: + { + integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-async-to-generator@7.28.6": + resolution: + { + integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-block-scoped-functions@7.27.1": + resolution: + { + integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-block-scoping@7.28.6": + resolution: + { + integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-class-properties@7.28.6": + resolution: + { + integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-class-static-block@7.28.6": + resolution: + { + integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.12.0 + + "@babel/plugin-transform-classes@7.28.6": + resolution: + { + integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-computed-properties@7.28.6": + resolution: + { + integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-destructuring@7.28.5": + resolution: + { + integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-dotall-regex@7.28.6": + resolution: + { + integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-duplicate-keys@7.27.1": + resolution: + { + integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0": + resolution: + { + integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-transform-dynamic-import@7.27.1": + resolution: + { + integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-explicit-resource-management@7.28.6": + resolution: + { + integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-exponentiation-operator@7.28.6": + resolution: + { + integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-export-namespace-from@7.27.1": + resolution: + { + integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-for-of@7.27.1": + resolution: + { + integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-function-name@7.27.1": + resolution: + { + integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-json-strings@7.28.6": + resolution: + { + integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-literals@7.27.1": + resolution: + { + integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-logical-assignment-operators@7.28.6": + resolution: + { + integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-member-expression-literals@7.27.1": + resolution: + { + integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-modules-amd@7.27.1": + resolution: + { + integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-modules-commonjs@7.28.6": + resolution: + { + integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-modules-systemjs@7.29.0": + resolution: + { + integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-modules-umd@7.27.1": + resolution: + { + integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-named-capturing-groups-regex@7.29.0": + resolution: + { + integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-transform-new-target@7.27.1": + resolution: + { + integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-nullish-coalescing-operator@7.28.6": + resolution: + { + integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-numeric-separator@7.28.6": + resolution: + { + integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-object-rest-spread@7.28.6": + resolution: + { + integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-object-super@7.27.1": + resolution: + { + integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-optional-catch-binding@7.28.6": + resolution: + { + integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-optional-chaining@7.28.6": + resolution: + { + integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-parameters@7.27.7": + resolution: + { + integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-private-methods@7.28.6": + resolution: + { + integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-private-property-in-object@7.28.6": + resolution: + { + integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-property-literals@7.27.1": + resolution: + { + integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-regenerator@7.29.0": + resolution: + { + integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-regexp-modifiers@7.28.6": + resolution: + { + integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/plugin-transform-reserved-words@7.27.1": + resolution: + { + integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-shorthand-properties@7.27.1": + resolution: + { + integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-spread@7.28.6": + resolution: + { + integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-sticky-regex@7.27.1": + resolution: + { + integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-template-literals@7.27.1": + resolution: + { + integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-typeof-symbol@7.27.1": + resolution: + { + integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-unicode-escapes@7.27.1": + resolution: + { + integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-unicode-property-regex@7.28.6": + resolution: + { + integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-unicode-regex@7.27.1": + resolution: + { + integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-transform-unicode-sets-regex@7.28.6": + resolution: + { + integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/preset-env@7.29.0": + resolution: + { + integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/preset-modules@0.1.6-no-external-plugins": + resolution: + { + integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + "@babel/runtime@7.28.6": + resolution: + { + integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==, + } + engines: { node: ">=6.9.0" } + + "@babel/template@7.28.6": + resolution: + { + integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/traverse@7.29.0": + resolution: + { + integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==, + } + engines: { node: ">=6.9.0" } + + "@babel/types@7.29.0": + resolution: + { + integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==, + } + engines: { node: ">=6.9.0" } + + "@cacheable/memory@2.0.7": + resolution: + { + integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==, + } + + "@cacheable/utils@2.3.4": + resolution: + { + integrity: sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==, + } + + "@codemirror/autocomplete@6.20.0": + resolution: + { + integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==, + } + + "@codemirror/commands@6.10.2": + resolution: + { + integrity: sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==, + } + + "@codemirror/lang-css@6.3.1": + resolution: + { + integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==, + } + + "@codemirror/lang-html@6.4.11": + resolution: + { + integrity: sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==, + } + + "@codemirror/lang-javascript@6.2.4": + resolution: + { + integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==, + } + + "@codemirror/lang-xml@6.1.0": + resolution: + { + integrity: sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==, + } + + "@codemirror/language@6.12.1": + resolution: + { + integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==, + } + + "@codemirror/lint@6.9.4": + resolution: + { + integrity: sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw==, + } + + "@codemirror/search@6.6.0": + resolution: + { + integrity: sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==, + } + + "@codemirror/state@6.5.4": + resolution: + { + integrity: sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==, + } + + "@codemirror/view@6.39.14": + resolution: + { + integrity: sha512-WJcvgHm/6Q7dvGT0YFv/6PSkoc36QlR0VCESS6x9tGsnF1lWLmmYxOgX3HH6v8fo6AvSLgpcs+H0Olre6MKXlg==, + } + + "@colors/colors@1.5.0": + resolution: + { + integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==, + } + engines: { node: ">=0.1.90" } + + "@commitlint/cli@20.4.2": + resolution: + { + integrity: sha512-YjYSX2yj/WsVoxh9mNiymfFS2ADbg2EK4+1WAsMuckwKMCqJ5PDG0CJU/8GvmHWcv4VRB2V02KqSiecRksWqZQ==, + } + engines: { node: ">=v18" } + hasBin: true + + "@commitlint/config-conventional@20.4.2": + resolution: + { + integrity: sha512-rwkTF55q7Q+6dpSKUmJoScV0f3EpDlWKw2UPzklkLS4o5krMN1tPWAVOgHRtyUTMneIapLeQwaCjn44Td6OzBQ==, + } + engines: { node: ">=v18" } + + "@commitlint/config-validator@20.4.0": + resolution: + { + integrity: sha512-zShmKTF+sqyNOfAE0vKcqnpvVpG0YX8F9G/ZIQHI2CoKyK+PSdladXMSns400aZ5/QZs+0fN75B//3Q5CHw++w==, + } + engines: { node: ">=v18" } + + "@commitlint/ensure@20.4.1": + resolution: + { + integrity: sha512-WLQqaFx1pBooiVvBrA1YfJNFqZF8wS/YGOtr5RzApDbV9tQ52qT5VkTsY65hFTnXhW8PcDfZLaknfJTmPejmlw==, + } + engines: { node: ">=v18" } + + "@commitlint/execute-rule@20.0.0": + resolution: + { + integrity: sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==, + } + engines: { node: ">=v18" } + + "@commitlint/format@20.4.0": + resolution: + { + integrity: sha512-i3ki3WR0rgolFVX6r64poBHXM1t8qlFel1G1eCBvVgntE3fCJitmzSvH5JD/KVJN/snz6TfaX2CLdON7+s4WVQ==, + } + engines: { node: ">=v18" } + + "@commitlint/is-ignored@20.4.1": + resolution: + { + integrity: sha512-In5EO4JR1lNsAv1oOBBO24V9ND1IqdAJDKZiEpdfjDl2HMasAcT7oA+5BKONv1pRoLG380DGPE2W2RIcUwdgLA==, + } + engines: { node: ">=v18" } + + "@commitlint/lint@20.4.2": + resolution: + { + integrity: sha512-buquzNRtFng6xjXvBU1abY/WPEEjCgUipNQrNmIWe8QuJ6LWLtei/LDBAzEe5ASm45+Q9L2Xi3/GVvlj50GAug==, + } + engines: { node: ">=v18" } + + "@commitlint/load@20.4.0": + resolution: + { + integrity: sha512-Dauup/GfjwffBXRJUdlX/YRKfSVXsXZLnINXKz0VZkXdKDcaEILAi9oflHGbfydonJnJAbXEbF3nXPm9rm3G6A==, + } + engines: { node: ">=v18" } + + "@commitlint/message@20.4.0": + resolution: + { + integrity: sha512-B5lGtvHgiLAIsK5nLINzVW0bN5hXv+EW35sKhYHE8F7V9Uz1fR4tx3wt7mobA5UNhZKUNgB/+ldVMQE6IHZRyA==, + } + engines: { node: ">=v18" } + + "@commitlint/parse@20.4.1": + resolution: + { + integrity: sha512-XNtZjeRcFuAfUnhYrCY02+mpxwY4OmnvD3ETbVPs25xJFFz1nRo/25nHj+5eM+zTeRFvWFwD4GXWU2JEtoK1/w==, + } + engines: { node: ">=v18" } + + "@commitlint/read@20.4.0": + resolution: + { + integrity: sha512-QfpFn6/I240ySEGv7YWqho4vxqtPpx40FS7kZZDjUJ+eHxu3azfhy7fFb5XzfTqVNp1hNoI3tEmiEPbDB44+cg==, + } + engines: { node: ">=v18" } + + "@commitlint/resolve-extends@20.4.0": + resolution: + { + integrity: sha512-ay1KM8q0t+/OnlpqXJ+7gEFQNlUtSU5Gxr8GEwnVf2TPN3+ywc5DzL3JCxmpucqxfHBTFwfRMXxPRRnR5Ki20g==, + } + engines: { node: ">=v18" } + + "@commitlint/rules@20.4.2": + resolution: + { + integrity: sha512-oz83pnp5Yq6uwwTAabuVQPNlPfeD2Y5ZjMb7Wx8FSUlu4sLYJjbBWt8031Z0osCFPfHzAwSYrjnfDFKtuSMdKg==, + } + engines: { node: ">=v18" } + + "@commitlint/to-lines@20.0.0": + resolution: + { + integrity: sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==, + } + engines: { node: ">=v18" } + + "@commitlint/top-level@20.4.0": + resolution: + { + integrity: sha512-NDzq8Q6jmFaIIBC/GG6n1OQEaHdmaAAYdrZRlMgW6glYWGZ+IeuXmiymDvQNXPc82mVxq2KiE3RVpcs+1OeDeA==, + } + engines: { node: ">=v18" } + + "@commitlint/types@20.4.0": + resolution: + { + integrity: sha512-aO5l99BQJ0X34ft8b0h7QFkQlqxC6e7ZPVmBKz13xM9O8obDaM1Cld4sQlJDXXU/VFuUzQ30mVtHjVz74TuStw==, + } + engines: { node: ">=v18" } + + "@csstools/cascade-layer-name-parser@3.0.0": + resolution: + { + integrity: sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + + "@csstools/color-helpers@6.0.1": + resolution: + { + integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==, + } + engines: { node: ">=20.19.0" } + + "@csstools/css-calc@3.1.1": + resolution: + { + integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + + "@csstools/css-color-parser@4.0.1": + resolution: + { + integrity: sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + + "@csstools/css-parser-algorithms@4.0.0": + resolution: + { + integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + "@csstools/css-tokenizer": ^4.0.0 + + "@csstools/css-syntax-patches-for-csstree@1.0.27": + resolution: + { + integrity: sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==, + } + + "@csstools/css-tokenizer@4.0.0": + resolution: + { + integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==, + } + engines: { node: ">=20.19.0" } + + "@csstools/media-query-list-parser@5.0.0": + resolution: + { + integrity: sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + "@csstools/css-parser-algorithms": ^4.0.0 + "@csstools/css-tokenizer": ^4.0.0 + + "@csstools/postcss-alpha-function@2.0.2": + resolution: + { + integrity: sha512-EXdJC5fds0h1KqoioUBkcYPZvcNKR64jrGkbqlDNbMU3FP1MzLEr/QJR8bj/bu53TJFIgkc9WvKcpbwVqZ4WPg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-cascade-layers@6.0.0": + resolution: + { + integrity: sha512-WhsECqmrEZQGqaPlBA7JkmF/CJ2/+wetL4fkL9sOPccKd32PQ1qToFM6gqSI5rkpmYqubvbxjEJhyMTHYK0vZQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-color-function-display-p3-linear@2.0.1": + resolution: + { + integrity: sha512-blnzzMkMswoagp1u3JS1OiiTuQCW1F+lQEtlxu2BXhTUmEeKHhSgrrAceF7s4bwZOwKYbkxuw/FC9Ni/zxB7Xw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-color-function@5.0.1": + resolution: + { + integrity: sha512-SNU4o63+oZpB7ufkTmj3FholvMtJwuyIWqTOVOxnZjNDFEg1hwdbnPjoytZVgKRQGkvkHdAS0uZWn0zH+ZwXCQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-color-mix-function@4.0.1": + resolution: + { + integrity: sha512-B9XBCd8cmHVwnc5YTn2YVXOlNMTNwuPIpJQ87665vaNdfNorVWz8JhAAv7Vq0v66TA6htE7+QW0OidL/QV0tiA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-color-mix-variadic-function-arguments@2.0.1": + resolution: + { + integrity: sha512-PV5nv9EHsEsvC5GlVqAHa1PznP/qZxFAIABImrkGJUbSoFUTwpnPch/dYSKw52CQ0aNnwCqMHoM29wDwmpVLqw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-content-alt-text@3.0.0": + resolution: + { + integrity: sha512-OHa+4aCcrJtHpPWB3zptScHwpS1TUbeLR4uO0ntIz0Su/zw9SoWkVu+tDMSySSAsNtNSI3kut4fTliFwIsrHxA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-contrast-color-function@3.0.1": + resolution: + { + integrity: sha512-Zy2gyAPsUyoAUkmBjLbWcXJhglM+toBRpNegyJc/LTHpSpIbMKVmByGQ+VSw01E1Pov8Dk/fgEs9hd11xtGC8g==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-exponential-functions@3.0.0": + resolution: + { + integrity: sha512-KCtnlZw1VrDCAbYxE44rUHONYAkjhh0/iS5T3L2K5OHuvoSEvxDjJO82pRwTmsRxVtSiC+syPjx2k2xsqHOM7w==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-font-format-keywords@5.0.0": + resolution: + { + integrity: sha512-M1EjCe/J3u8fFhOZgRci74cQhJ7R0UFBX6T+WqoEvjrr8hVfMiV+HTYrzxLY5OW8YllvXYr5Q5t5OvJbsUSeDg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-gamut-mapping@3.0.1": + resolution: + { + integrity: sha512-0S7D+gArVXsgRDxjoNv8g2QlaIi/SegqdlTMgVwowaPSyxaZsVnwrhShvmlpoLOVHmpJfHKGiXzn1Hc1BcZCzQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-gradients-interpolation-method@6.0.1": + resolution: + { + integrity: sha512-Y5dxOstuUCdmU1tuEB/EgKxDw+/DAZes4gQeitb/H0S5khmjT24CfbVa/l2ZelNCEEq9KjxqO2cjwDV2vqj62w==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-hwb-function@5.0.1": + resolution: + { + integrity: sha512-9f8TA/B8iEpzF0y4Z6qPVfP9nMp2ti10OFbtyDtoBz3+eK0KPV4CCCjTwYIpPRopLgctFZt7xqmOxA7JgAJEug==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-ic-unit@5.0.0": + resolution: + { + integrity: sha512-/ws5d6c4uKqfM9zIL3ugcGI+3fvZEOOkJHNzAyTAGJIdZ+aSL9BVPNlHGV4QzmL0vqBSCOdU3+rhcMEj3+KzYw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-initial@3.0.0": + resolution: + { + integrity: sha512-UVUrFmrTQyLomVepnjWlbBg7GoscLmXLwYFyjbcEnmpeGW7wde6lNpx5eM3eVwZI2M+7hCE3ykYnAsEPLcLa+Q==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-is-pseudo-class@6.0.0": + resolution: + { + integrity: sha512-1Hdy/ykg9RDo8vU8RiM2o+RaXO39WpFPaIkHxlAEJFofle/lc33tdQMKhBk3jR/Fe+uZNLOs3HlowFafyFptVw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-light-dark-function@3.0.0": + resolution: + { + integrity: sha512-s++V5/hYazeRUCYIn2lsBVzUsxdeC46gtwpgW6lu5U/GlPOS5UTDT14kkEyPgXmFbCvaWLREqV7YTMJq1K3G6w==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-logical-float-and-clear@4.0.0": + resolution: + { + integrity: sha512-NGzdIRVj/VxOa/TjVdkHeyiJoDihONV0+uB0csUdgWbFFr8xndtfqK8iIGP9IKJzco+w0hvBF2SSk2sDSTAnOQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-logical-overflow@3.0.0": + resolution: + { + integrity: sha512-5cRg93QXVskM0MNepHpPcL0WLSf5Hncky0DrFDQY/4ozbH5lH7SX5ejayVpNTGSX7IpOvu7ykQDLOdMMGYzwpA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-logical-overscroll-behavior@3.0.0": + resolution: + { + integrity: sha512-82Jnl/5Wi5jb19nQE1XlBHrZcNL3PzOgcj268cDkfwf+xi10HBqufGo1Unwf5n8bbbEFhEKgyQW+vFsc9iY1jw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-logical-resize@4.0.0": + resolution: + { + integrity: sha512-L0T3q0gei/tGetCGZU0c7VN77VTivRpz1YZRNxjXYmW+85PKeI6U9YnSvDqLU2vBT2uN4kLEzfgZ0ThIZpN18A==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-logical-viewport-units@4.0.0": + resolution: + { + integrity: sha512-TA3AqVN/1IH3dKRC2UUWvprvwyOs2IeD7FDZk5Hz20w4q33yIuSg0i0gjyTUkcn90g8A4n7QpyZ2AgBrnYPnnA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-media-minmax@3.0.0": + resolution: + { + integrity: sha512-42szvyZ/oqG7NSvBQOGq1IaJaHR6mr/iXqqjW8/JuIajIHRs9HcJR5ExC4vbyCqk+fr7/DIOhm5ZrELBytLDsw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-media-queries-aspect-ratio-number-values@4.0.0": + resolution: + { + integrity: sha512-FDdC3lbrj8Vr0SkGIcSLTcRB7ApG6nlJFxOxkEF2C5hIZC1jtgjISFSGn/WjFdVkn8Dqe+Vx9QXI3axS2w1XHw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-mixins@1.0.0": + resolution: + { + integrity: sha512-rz6qjT2w9L3k65jGc2dX+3oGiSrYQ70EZPDrINSmSVoVys7lLBFH0tvEa8DW2sr9cbRVD/W+1sy8+7bfu0JUfg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-nested-calc@5.0.0": + resolution: + { + integrity: sha512-aPSw8P60e/i9BEfugauhikBqgjiwXcw3I9o4vXs+hktl4NSTgZRI0QHimxk9mst8N01A2TKDBxOln3mssRxiHQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-normalize-display-values@5.0.1": + resolution: + { + integrity: sha512-FcbEmoxDEGYvm2W3rQzVzcuo66+dDJjzzVDs+QwRmZLHYofGmMGwIKPqzF86/YW+euMDa7sh1xjWDvz/fzByZQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-oklab-function@5.0.1": + resolution: + { + integrity: sha512-Ql+X4zu29ITihxHKcCFEU84ww+Nkv44M2s0fT7Nv4iQYlQ4+liF6v9RL0ezeogeiLRNLLC6yh0ay1PHpmaNIgQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-position-area-property@2.0.0": + resolution: + { + integrity: sha512-TeEfzsJGB23Syv7yCm8AHCD2XTFujdjr9YYu9ebH64vnfCEvY4BG319jXAYSlNlf3Yc9PNJ6WnkDkUF5XVgSKQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-progressive-custom-properties@5.0.0": + resolution: + { + integrity: sha512-NsJoZ89rxmDrUsITf8QIk5w+lQZQ8Xw5K6cLFG+cfiffsLYHb3zcbOOrHLetGl1WIhjWWQ4Cr8MMrg46Q+oACg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-property-rule-prelude-list@2.0.0": + resolution: + { + integrity: sha512-qcMAkc9AhpzHgmQCD8hoJgGYifcOAxd1exXjjxilMM6euwRE619xDa4UsKBCv/v4g+sS63sd6c29LPM8s2ylSQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-random-function@3.0.0": + resolution: + { + integrity: sha512-H/Zt5o9NAd8mowq3XRy8uU19wOEe8sbKyKOKxrzOdG0rz2maA4fLcXc9MQucdm3s4zMDfVJtCqvwrLP7lKWybA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-relative-color-syntax@4.0.1": + resolution: + { + integrity: sha512-zRLO9xMGtCCT0FTpTsaGI6cmdzJKbwWjg92AuczlSDuriEAPEJL+ZJ4jDyw51p23DfoAFgK8soB/LyoY1kFOLQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-scope-pseudo-class@5.0.0": + resolution: + { + integrity: sha512-kBrBFJcAji3MSHS4qQIihPvJfJC5xCabXLbejqDMiQi+86HD4eMBiTayAo46Urg7tlEmZZQFymFiJt+GH6nvXw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-sign-functions@2.0.0": + resolution: + { + integrity: sha512-32Bw7++8ToSLMEOSJUuxJsAJJdsIfgeD1dYPKRCk9/fTciVZ8MjkPXypwiXIo7xIJk0h5CJz6QUkDoc6dcAJ7Q==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-stepped-value-functions@5.0.0": + resolution: + { + integrity: sha512-NueCSNbaq7QtAj6QwseMqOlM3C8nN2GWaPwd2Uw+IOYAbGvO/84BxUtNeZljeOmqJX61hwSNhLfwmgJXgY0W5A==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-syntax-descriptor-syntax-production@2.0.0": + resolution: + { + integrity: sha512-elYcbdiBXAkPqvojB9kIBRuHY6htUhjSITtFQ+XiXnt6SvZCbNGxQmaaw6uZ7SPHu/+i/XVjzIt09/1k3SIerQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-system-ui-font-family@2.0.0": + resolution: + { + integrity: sha512-FyGZCgchFImFyiHS2x3rD5trAqatf/x23veBLTIgbaqyFfna6RNBD+Qf8HRSjt6HGMXOLhAjxJ3OoZg0bbn7Qw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-text-decoration-shorthand@5.0.2": + resolution: + { + integrity: sha512-0VUTt79lfQ2LGQLfyOBeqpinDLzOf3w+tlA1Re/KjSOc86H6tRz6TeXbISrBSJlfM1fYKNmBNw+ON8Ovy6aNeg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-trigonometric-functions@5.0.0": + resolution: + { + integrity: sha512-isjkD3l1MVjanGuaS7RIYP/9txZKbZ8eQPaUHoxEWmySm3k6KutSepzPINL6MXyyi0ZUijZcktA++/L66IK71A==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/postcss-unset-value@5.0.0": + resolution: + { + integrity: sha512-EoO54sS2KCIfesvHyFYAW99RtzwHdgaJzhl7cqKZSaMYKZv3fXSOehDjAQx8WZBKn1JrMd7xJJI1T1BxPF7/jA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@csstools/selector-resolve-nested@4.0.0": + resolution: + { + integrity: sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss-selector-parser: ^7.1.1 + + "@csstools/selector-specificity@6.0.0": + resolution: + { + integrity: sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss-selector-parser: ^7.1.1 + + "@csstools/utilities@3.0.0": + resolution: + { + integrity: sha512-etDqA/4jYvOGBM6yfKCOsEXfH96BKztZdgGmGqKi2xHnDe0ILIBraRspwgYatJH9JsCZ5HCGoCst8w18EKOAdg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + "@emnapi/runtime@1.8.1": + resolution: + { + integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==, + } + + "@epic-web/invariant@1.0.0": + resolution: + { + integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==, + } + + "@esbuild/aix-ppc64@0.27.3": + resolution: + { + integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [aix] + + "@esbuild/android-arm64@0.27.3": + resolution: + { + integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [android] + + "@esbuild/android-arm@0.27.3": + resolution: + { + integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [android] + + "@esbuild/android-x64@0.27.3": + resolution: + { + integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [android] + + "@esbuild/darwin-arm64@0.27.3": + resolution: + { + integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [darwin] + + "@esbuild/darwin-x64@0.27.3": + resolution: + { + integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [darwin] + + "@esbuild/freebsd-arm64@0.27.3": + resolution: + { + integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [freebsd] + + "@esbuild/freebsd-x64@0.27.3": + resolution: + { + integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [freebsd] + + "@esbuild/linux-arm64@0.27.3": + resolution: + { + integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [linux] + + "@esbuild/linux-arm@0.27.3": + resolution: + { + integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [linux] + + "@esbuild/linux-ia32@0.27.3": + resolution: + { + integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [linux] + + "@esbuild/linux-loong64@0.27.3": + resolution: + { + integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==, + } + engines: { node: ">=18" } + cpu: [loong64] + os: [linux] + + "@esbuild/linux-mips64el@0.27.3": + resolution: + { + integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==, + } + engines: { node: ">=18" } + cpu: [mips64el] + os: [linux] + + "@esbuild/linux-ppc64@0.27.3": + resolution: + { + integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [linux] + + "@esbuild/linux-riscv64@0.27.3": + resolution: + { + integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==, + } + engines: { node: ">=18" } + cpu: [riscv64] + os: [linux] + + "@esbuild/linux-s390x@0.27.3": + resolution: + { + integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==, + } + engines: { node: ">=18" } + cpu: [s390x] + os: [linux] + + "@esbuild/linux-x64@0.27.3": + resolution: + { + integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [linux] + + "@esbuild/netbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [netbsd] + + "@esbuild/netbsd-x64@0.27.3": + resolution: + { + integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [netbsd] + + "@esbuild/openbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openbsd] + + "@esbuild/openbsd-x64@0.27.3": + resolution: + { + integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [openbsd] + + "@esbuild/openharmony-arm64@0.27.3": + resolution: + { + integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openharmony] + + "@esbuild/sunos-x64@0.27.3": + resolution: + { + integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [sunos] + + "@esbuild/win32-arm64@0.27.3": + resolution: + { + integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [win32] + + "@esbuild/win32-ia32@0.27.3": + resolution: + { + integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [win32] + + "@esbuild/win32-x64@0.27.3": + resolution: + { + integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [win32] + + "@eslint-community/eslint-utils@4.9.1": + resolution: + { + integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + "@eslint-community/regexpp@4.12.2": + resolution: + { + integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + "@eslint/config-array@0.23.1": + resolution: + { + integrity: sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/config-helpers@0.5.2": + resolution: + { + integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/core@1.1.0": + resolution: + { + integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/eslintrc@3.3.3": + resolution: + { + integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@eslint/js@10.0.1": + resolution: + { + integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + "@eslint/object-schema@3.0.1": + resolution: + { + integrity: sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@eslint/plugin-kit@0.6.0": + resolution: + { + integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + "@floating-ui/core@1.7.4": + resolution: + { + integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==, + } + + "@floating-ui/dom@1.7.5": + resolution: + { + integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==, + } + + "@floating-ui/utils@0.2.10": + resolution: + { + integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==, + } + + "@foliojs-fork/fontkit@1.9.2": + resolution: + { + integrity: sha512-IfB5EiIb+GZk+77TRB86AHroVaqfq8JRFlUbz0WEwsInyCG0epX2tCPOy+UfaWPju30DeVoUAXfzWXmhn753KA==, + } + + "@foliojs-fork/linebreak@1.1.2": + resolution: + { + integrity: sha512-ZPohpxxbuKNE0l/5iBJnOAfUaMACwvUIKCvqtWGKIMv1lPYoNjYXRfhi9FeeV9McBkBLxsMFWTVVhHJA8cyzvg==, + } + + "@foliojs-fork/pdfkit@0.15.3": + resolution: + { + integrity: sha512-Obc0Wmy3bm7BINFVvPhcl2rnSSK61DQrlHU8aXnAqDk9LCjWdUOPwhgD8Ywz5VtuFjRxmVOM/kQ/XLIBjDvltw==, + } + + "@foliojs-fork/restructure@2.0.2": + resolution: + { + integrity: sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==, + } + + "@github/clipboard-copy-element@1.3.0": + resolution: + { + integrity: sha512-wyntkQkwoLbLo+Hqg2LIVMXDIzcvUb9bSDz+clX6nVJItwzh103rHxdXFRZD+DmxVbuEW5xSznYQXkz1jZT+xg==, + } + + "@github/hotkey@3.1.1": + resolution: + { + integrity: sha512-H30I6XDO3gFSgLuEuHoMBRZG9c3uCKNdAcYklL1FaZDPdU1bXfgjnpzGDPcUr0U6eGQ+T3XLY9slatwZYWL1dA==, + } + + "@github/markdown-toolbar-element@2.2.3": + resolution: + { + integrity: sha512-AlquKGee+IWiAMYVB0xyHFZRMnu4n3X4HTvJHu79GiVJ1ojTukCWyxMlF5NMsecoLcBKsuBhx3QPv2vkE/zQ0A==, + } + + "@github/relative-time-element@5.0.0": + resolution: + { + integrity: sha512-L/2r0DNR/rMbmHWcsdmhtOiy2gESoGOhItNFD4zJ3nZfHl79Dx3N18Vfx/pYr2lruMOdk1cJZb4wEumm+Dxm1w==, + } + + "@humanfs/core@0.19.1": + resolution: + { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: ">=18.18.0" } + + "@humanfs/node@0.16.7": + resolution: + { + integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==, + } + engines: { node: ">=18.18.0" } + + "@humanwhocodes/module-importer@1.0.1": + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: ">=12.22" } + + "@humanwhocodes/retry@0.4.3": + resolution: + { + integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, + } + engines: { node: ">=18.18" } + + "@img/colour@1.0.0": + resolution: + { + integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==, + } + engines: { node: ">=18" } + + "@img/sharp-darwin-arm64@0.34.5": + resolution: + { + integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [darwin] + + "@img/sharp-darwin-x64@0.34.5": + resolution: + { + integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-darwin-arm64@1.2.4": + resolution: + { + integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==, + } + cpu: [arm64] + os: [darwin] + + "@img/sharp-libvips-darwin-x64@1.2.4": + resolution: + { + integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==, + } + cpu: [x64] + os: [darwin] + + "@img/sharp-libvips-linux-arm64@1.2.4": + resolution: + { + integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-arm@1.2.4": + resolution: + { + integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-ppc64@1.2.4": + resolution: + { + integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-riscv64@1.2.4": + resolution: + { + integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-s390x@1.2.4": + resolution: + { + integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linux-x64@1.2.4": + resolution: + { + integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-libvips-linuxmusl-arm64@1.2.4": + resolution: + { + integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-libvips-linuxmusl-x64@1.2.4": + resolution: + { + integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-linux-arm64@0.34.5": + resolution: + { + integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-arm@0.34.5": + resolution: + { + integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-ppc64@0.34.5": + resolution: + { + integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-riscv64@0.34.5": + resolution: + { + integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-s390x@0.34.5": + resolution: + { + integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@img/sharp-linux-x64@0.34.5": + resolution: + { + integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@img/sharp-linuxmusl-arm64@0.34.5": + resolution: + { + integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@img/sharp-linuxmusl-x64@0.34.5": + resolution: + { + integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [linux] + libc: [musl] + + "@img/sharp-wasm32@0.34.5": + resolution: + { + integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [wasm32] + + "@img/sharp-win32-arm64@0.34.5": + resolution: + { + integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [arm64] + os: [win32] + + "@img/sharp-win32-ia32@0.34.5": + resolution: + { + integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [ia32] + os: [win32] + + "@img/sharp-win32-x64@0.34.5": + resolution: + { + integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + cpu: [x64] + os: [win32] + + "@isaacs/cliui@9.0.0": + resolution: + { + integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==, + } + engines: { node: ">=18" } + + "@jridgewell/gen-mapping@0.3.13": + resolution: + { + integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, + } + + "@jridgewell/remapping@2.3.5": + resolution: + { + integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, + } + + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/source-map@0.3.11": + resolution: + { + integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==, + } + + "@jridgewell/sourcemap-codec@1.5.5": + resolution: + { + integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, + } + + "@jridgewell/trace-mapping@0.3.31": + resolution: + { + integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, + } + + "@keyv/bigmap@1.3.1": + resolution: + { + integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==, + } + engines: { node: ">= 18" } + peerDependencies: + keyv: ^5.6.0 + + "@keyv/serialize@1.1.1": + resolution: + { + integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==, + } + + "@lezer/common@1.5.1": + resolution: + { + integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==, + } + + "@lezer/css@1.3.1": + resolution: + { + integrity: sha512-PYAKeUVBo3HFThruRyp/iK91SwiZJnzXh8QzkQlwijB5y+N5iB28+iLk78o2zmKqqV0uolNhCwFqB8LA7b0Svg==, + } + + "@lezer/highlight@1.2.3": + resolution: + { + integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==, + } + + "@lezer/html@1.3.13": + resolution: + { + integrity: sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==, + } + + "@lezer/javascript@1.5.4": + resolution: + { + integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==, + } + + "@lezer/lr@1.4.8": + resolution: + { + integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==, + } + + "@lezer/xml@1.0.6": + resolution: + { + integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==, + } + + "@lit-labs/ssr-dom-shim@1.5.1": + resolution: + { + integrity: sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==, + } + + "@lit/context@1.1.6": + resolution: + { + integrity: sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==, + } + + "@lit/reactive-element@2.1.2": + resolution: + { + integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==, + } + + "@marijn/find-cluster-break@1.0.2": + resolution: + { + integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==, + } + + "@nodelib/fs.scandir@2.1.5": + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: ">= 8" } + + "@nodelib/fs.stat@2.0.5": + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: ">= 8" } + + "@nodelib/fs.walk@1.2.8": + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: ">= 8" } + + "@octokit/auth-token@6.0.0": + resolution: + { + integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==, + } + engines: { node: ">= 20" } + + "@octokit/core@7.0.6": + resolution: + { + integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==, + } + engines: { node: ">= 20" } + + "@octokit/endpoint@11.0.3": + resolution: + { + integrity: sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==, + } + engines: { node: ">= 20" } + + "@octokit/graphql@9.0.3": + resolution: + { + integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==, + } + engines: { node: ">= 20" } + + "@octokit/openapi-types@27.0.0": + resolution: + { + integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==, + } + + "@octokit/plugin-paginate-rest@14.0.0": + resolution: + { + integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==, + } + engines: { node: ">= 20" } + peerDependencies: + "@octokit/core": ">=6" + + "@octokit/plugin-retry@8.1.0": + resolution: + { + integrity: sha512-O1FZgXeiGb2sowEr/hYTr6YunGdSAFWnr2fyW39Ah85H8O33ELASQxcvOFF5LE6Tjekcyu2ms4qAzJVhSaJxTw==, + } + engines: { node: ">= 20" } + peerDependencies: + "@octokit/core": ">=7" + + "@octokit/plugin-throttling@11.0.3": + resolution: + { + integrity: sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==, + } + engines: { node: ">= 20" } + peerDependencies: + "@octokit/core": ^7.0.0 + + "@octokit/request-error@7.1.0": + resolution: + { + integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==, + } + engines: { node: ">= 20" } + + "@octokit/request@10.0.7": + resolution: + { + integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==, + } + engines: { node: ">= 20" } + + "@octokit/types@16.0.0": + resolution: + { + integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==, + } + + "@patternfly/elements@4.3.1": + resolution: + { + integrity: sha512-MRVwxcam+ACyy+0Xy5igPr+LcSVRbX422NGPE4I7WRuwAEhRBA3BayyLi8mNVKXpLLZbk8EtJ17kM30PcMziMw==, + } + + "@patternfly/icons@1.0.3": + resolution: + { + integrity: sha512-8BARaCFBUZU2/TxuOQb8R2/VIpxGMnFwdw5ddT1AMnR2KSifdo+d05SgZtVmFkOIAOA0oCo/YKRgSORDA47wig==, + } + + "@patternfly/pfe-core@5.0.6": + resolution: + { + integrity: sha512-95j0BDltTTVQzOSIqpiZXQYzm1kuwqpHeB/7/QOjmZP3wtvYcaccnE/2dldKF68rn0Rwgk9xbgz7MR8/CnKFgQ==, + } + + "@pkgr/core@0.2.9": + resolution: + { + integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==, + } + engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + + "@pnpm/config.env-replace@1.1.0": + resolution: + { + integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==, + } + engines: { node: ">=12.22.0" } + + "@pnpm/network.ca-file@1.0.2": + resolution: + { + integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==, + } + engines: { node: ">=12.22.0" } + + "@pnpm/npm-conf@3.0.2": + resolution: + { + integrity: sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==, + } + engines: { node: ">=12" } + + "@polka/url@1.0.0-next.29": + resolution: + { + integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==, + } + + "@rollup/plugin-babel@5.3.1": + resolution: + { + integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==, + } + engines: { node: ">= 10.0.0" } + peerDependencies: + "@babel/core": ^7.0.0 + "@types/babel__core": ^7.1.9 + rollup: ^1.20.0||^2.0.0 + peerDependenciesMeta: + "@types/babel__core": + optional: true + + "@rollup/plugin-node-resolve@15.3.1": + resolution: + { + integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + "@rollup/plugin-replace@2.4.2": + resolution: + { + integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==, + } + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + + "@rollup/plugin-terser@0.4.4": + resolution: + { + integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + "@rollup/pluginutils@3.1.0": + resolution: + { + integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==, + } + engines: { node: ">= 8.0.0" } + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + "@rollup/pluginutils@5.3.0": + resolution: + { + integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + "@rollup/rollup-android-arm-eabi@4.57.1": + resolution: + { + integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==, + } + cpu: [arm] + os: [android] + + "@rollup/rollup-android-arm64@4.57.1": + resolution: + { + integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==, + } + cpu: [arm64] + os: [android] + + "@rollup/rollup-darwin-arm64@4.57.1": + resolution: + { + integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==, + } + cpu: [arm64] + os: [darwin] + + "@rollup/rollup-darwin-x64@4.57.1": + resolution: + { + integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==, + } + cpu: [x64] + os: [darwin] + + "@rollup/rollup-freebsd-arm64@4.57.1": + resolution: + { + integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==, + } + cpu: [arm64] + os: [freebsd] + + "@rollup/rollup-freebsd-x64@4.57.1": + resolution: + { + integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==, + } + cpu: [x64] + os: [freebsd] + + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": + resolution: + { + integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==, + } + cpu: [arm] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-arm-musleabihf@4.57.1": + resolution: + { + integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==, + } + cpu: [arm] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-arm64-gnu@4.57.1": + resolution: + { + integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==, + } + cpu: [arm64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-arm64-musl@4.57.1": + resolution: + { + integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==, + } + cpu: [arm64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-loong64-gnu@4.57.1": + resolution: + { + integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==, + } + cpu: [loong64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-loong64-musl@4.57.1": + resolution: + { + integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==, + } + cpu: [loong64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-ppc64-gnu@4.57.1": + resolution: + { + integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==, + } + cpu: [ppc64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-ppc64-musl@4.57.1": + resolution: + { + integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==, + } + cpu: [ppc64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-riscv64-gnu@4.57.1": + resolution: + { + integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==, + } + cpu: [riscv64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-riscv64-musl@4.57.1": + resolution: + { + integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==, + } + cpu: [riscv64] + os: [linux] + libc: [musl] + + "@rollup/rollup-linux-s390x-gnu@4.57.1": + resolution: + { + integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==, + } + cpu: [s390x] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-x64-gnu@4.57.1": + resolution: + { + integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==, + } + cpu: [x64] + os: [linux] + libc: [glibc] + + "@rollup/rollup-linux-x64-musl@4.57.1": + resolution: + { + integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==, + } + cpu: [x64] + os: [linux] + libc: [musl] + + "@rollup/rollup-openbsd-x64@4.57.1": + resolution: + { + integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==, + } + cpu: [x64] + os: [openbsd] + + "@rollup/rollup-openharmony-arm64@4.57.1": + resolution: + { + integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==, + } + cpu: [arm64] + os: [openharmony] + + "@rollup/rollup-win32-arm64-msvc@4.57.1": + resolution: + { + integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==, + } + cpu: [arm64] + os: [win32] + + "@rollup/rollup-win32-ia32-msvc@4.57.1": + resolution: + { + integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==, + } + cpu: [ia32] + os: [win32] + + "@rollup/rollup-win32-x64-gnu@4.57.1": + resolution: + { + integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==, + } + cpu: [x64] + os: [win32] + + "@rollup/rollup-win32-x64-msvc@4.57.1": + resolution: + { + integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==, + } + cpu: [x64] + os: [win32] + + "@sec-ant/readable-stream@0.4.1": + resolution: + { + integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==, + } + + "@semantic-release/changelog@6.0.3": + resolution: + { + integrity: sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==, + } + engines: { node: ">=14.17" } + peerDependencies: + semantic-release: ">=18.0.0" + + "@semantic-release/commit-analyzer@13.0.1": + resolution: + { + integrity: sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==, + } + engines: { node: ">=20.8.1" } + peerDependencies: + semantic-release: ">=20.1.0" + + "@semantic-release/error@3.0.0": + resolution: + { + integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==, + } + engines: { node: ">=14.17" } + + "@semantic-release/error@4.0.0": + resolution: + { + integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==, + } + engines: { node: ">=18" } + + "@semantic-release/exec@7.1.0": + resolution: + { + integrity: sha512-4ycZ2atgEUutspPZ2hxO6z8JoQt4+y/kkHvfZ1cZxgl9WKJId1xPj+UadwInj+gMn2Gsv+fLnbrZ4s+6tK2TFQ==, + } + engines: { node: ">=20.8.1" } + peerDependencies: + semantic-release: ">=24.1.0" + + "@semantic-release/git@10.0.1": + resolution: + { + integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==, + } + engines: { node: ">=14.17" } + peerDependencies: + semantic-release: ">=18.0.0" + + "@semantic-release/github@12.0.6": + resolution: + { + integrity: sha512-aYYFkwHW3c6YtHwQF0t0+lAjlU+87NFOZuH2CvWFD0Ylivc7MwhZMiHOJ0FMpIgPpCVib/VUAcOwvrW0KnxQtA==, + } + engines: { node: ^22.14.0 || >= 24.10.0 } + peerDependencies: + semantic-release: ">=24.1.0" + + "@semantic-release/gitlab@13.3.0": + resolution: + { + integrity: sha512-E0q4qbTdVQZW8Siqz1YQjfSSXE2U/Z7lJasUlpHGRu+OYXsLCIU6o18scquofyP7CBxyKLIx7TDiLVRko1ekGw==, + } + engines: { node: ">=20.8.1" } + peerDependencies: + semantic-release: ">=20.1.0" + + "@semantic-release/npm@13.1.4": + resolution: + { + integrity: sha512-z5Fn9ftK1QQgFxMSuOd3DtYbTl4hWI2trCEvZcEJMQJy1/OBR0WHcxqzfVun455FSkHML8KgvPxJEa9MtZIBsg==, + } + engines: { node: ^22.14.0 || >= 24.10.0 } + peerDependencies: + semantic-release: ">=20.1.0" + + "@semantic-release/release-notes-generator@14.1.0": + resolution: + { + integrity: sha512-CcyDRk7xq+ON/20YNR+1I/jP7BYKICr1uKd1HHpROSnnTdGqOTburi4jcRiTYz0cpfhxSloQO3cGhnoot7IEkA==, + } + engines: { node: ">=20.8.1" } + peerDependencies: + semantic-release: ">=20.1.0" + + "@sindresorhus/is@4.6.0": + resolution: + { + integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==, + } + engines: { node: ">=10" } + + "@sindresorhus/is@7.2.0": + resolution: + { + integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==, + } + engines: { node: ">=18" } + + "@sindresorhus/merge-streams@2.3.0": + resolution: + { + integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==, + } + engines: { node: ">=18" } + + "@sindresorhus/merge-streams@4.0.0": + resolution: + { + integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==, + } + engines: { node: ">=18" } + + "@stencil/core@2.5.2": + resolution: + { + integrity: sha512-bgjPXkSzzg1WnTgVUm6m5ZzpKt602WmA/QljODAW1xVN40OHJdbGblzF/F6MFzqv2c5Cy30CB41arc8qADIdcQ==, + } + engines: { node: ">=12.10.0", npm: ">=6.0.0" } + hasBin: true + + "@surma/rollup-plugin-off-main-thread@2.2.3": + resolution: + { + integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==, + } + + "@tailwindcss/forms@0.5.11": + resolution: + { + integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==, + } + peerDependencies: + tailwindcss: ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1" + + "@tailwindcss/typography@0.5.19": + resolution: + { + integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==, + } + peerDependencies: + tailwindcss: ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + + "@types/eslint@9.6.1": + resolution: + { + integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==, + } + + "@types/esrecurse@4.3.1": + resolution: + { + integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==, + } + + "@types/estree@0.0.39": + resolution: + { + integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==, + } + + "@types/estree@1.0.8": + resolution: + { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } + + "@types/fscreen@1.0.4": + resolution: + { + integrity: sha512-TsjxyAUvlvuQyao9vNk0yES4nY07K9xoAbkhgXU948JG39EqlLxniWuW9OiZde9Q8ACSpu3fmbXXRAfb/l/HqQ==, + } + + "@types/geojson@7946.0.16": + resolution: + { + integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==, + } + + "@types/http-cache-semantics@4.2.0": + resolution: + { + integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==, + } + + "@types/json-schema@7.0.15": + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } + + "@types/leaflet@1.9.21": + resolution: + { + integrity: sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==, + } + + "@types/node@24.7.0": + resolution: + { + integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==, + } + + "@types/normalize-package-data@2.4.4": + resolution: + { + integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==, + } + + "@types/resolve@1.20.2": + resolution: + { + integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==, + } + + "@types/trusted-types@2.0.7": + resolution: + { + integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==, + } + + "@typescript-eslint/eslint-plugin@8.56.0": + resolution: + { + integrity: sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + "@typescript-eslint/parser": ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/parser@8.56.0": + resolution: + { + integrity: sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/project-service@8.56.0": + resolution: + { + integrity: sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/scope-manager@8.56.0": + resolution: + { + integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/tsconfig-utils@8.56.0": + resolution: + { + integrity: sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/type-utils@8.56.0": + resolution: + { + integrity: sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/types@8.56.0": + resolution: + { + integrity: sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@typescript-eslint/typescript-estree@8.56.0": + resolution: + { + integrity: sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/utils@8.56.0": + resolution: + { + integrity: sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + "@typescript-eslint/visitor-keys@8.56.0": + resolution: + { + integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + "@vime/core@5.4.1": + resolution: + { + integrity: sha512-ZFpV3xqZJ5tvh5rZOYKRh8zFzNIKr2ZcK6L75nJjFjbWt/ZmFF2nMBxtD9/hC4Xjk9v7hp1+P9cmctL674VFgA==, + } + + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: + { + integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, + } + engines: { node: ">=0.4.0" } + hasBin: true + + agent-base@7.1.4: + resolution: + { + integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==, + } + engines: { node: ">= 14" } + + aggregate-error@3.1.0: + resolution: + { + integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, + } + engines: { node: ">=8" } + + aggregate-error@5.0.0: + resolution: + { + integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==, + } + engines: { node: ">=18" } + + ajv@6.12.6: + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } + + ajv@8.18.0: + resolution: + { + integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==, + } + + all-contributors-cli@6.26.1: + resolution: + { + integrity: sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==, + } + engines: { node: ">=4" } + hasBin: true + + ansi-escapes@4.3.2: + resolution: + { + integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, + } + engines: { node: ">=8" } + + ansi-escapes@7.3.0: + resolution: + { + integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==, + } + engines: { node: ">=18" } + + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: ">=8" } + + ansi-regex@6.2.2: + resolution: + { + integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, + } + engines: { node: ">=12" } + + ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: ">=4" } + + ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: ">=8" } + + ansi-styles@6.2.3: + resolution: + { + integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, + } + engines: { node: ">=12" } + + ansis@4.2.0: + resolution: + { + integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==, + } + engines: { node: ">=14" } + + any-promise@1.3.0: + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } + + anymatch@3.1.3: + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: ">= 8" } + + arg@5.0.2: + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } + + argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + argv-formatter@1.0.0: + resolution: + { + integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==, + } + + array-buffer-byte-length@1.0.2: + resolution: + { + integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, + } + engines: { node: ">= 0.4" } + + array-ify@1.0.0: + resolution: + { + integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==, + } + + arraybuffer.prototype.slice@1.0.4: + resolution: + { + integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, + } + engines: { node: ">= 0.4" } + + astral-regex@2.0.0: + resolution: + { + integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==, + } + engines: { node: ">=8" } + + async-function@1.0.0: + resolution: + { + integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, + } + engines: { node: ">= 0.4" } + + async@3.2.6: + resolution: + { + integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, + } + + at-least-node@1.0.0: + resolution: + { + integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==, + } + engines: { node: ">= 4.0.0" } + + autoprefixer@10.4.24: + resolution: + { + integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==, + } + engines: { node: ^10 || ^12 || >=14 } + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: ">= 0.4" } + + babel-plugin-polyfill-corejs2@0.4.15: + resolution: + { + integrity: sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==, + } + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.0: + resolution: + { + integrity: sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==, + } + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.6: + resolution: + { + integrity: sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==, + } + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + + balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + balanced-match@3.0.1: + resolution: + { + integrity: sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==, + } + engines: { node: ">= 16" } + + balanced-match@4.0.3: + resolution: + { + integrity: sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==, + } + engines: { node: 20 || >=22 } + + base64-js@1.3.1: + resolution: + { + integrity: sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==, + } + + base64-js@1.5.1: + resolution: + { + integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, + } + + baseline-browser-mapping@2.10.0: + resolution: + { + integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + before-after-hook@4.0.0: + resolution: + { + integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==, + } + + binary-extensions@2.3.0: + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: ">=8" } + + birpc@2.9.0: + resolution: + { + integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==, + } + + bl@4.1.0: + resolution: + { + integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, + } + + boolbase@1.0.0: + resolution: + { + integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==, + } + + bottleneck@2.19.5: + resolution: + { + integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==, + } + + brace-expansion@1.1.12: + resolution: + { + integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, + } + + brace-expansion@2.0.2: + resolution: + { + integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, + } + + brace-expansion@5.0.2: + resolution: + { + integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==, + } + engines: { node: 20 || >=22 } + + braces@3.0.3: + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: ">=8" } + + brotli@1.3.3: + resolution: + { + integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==, + } + + browserslist@4.28.1: + resolution: + { + integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + + buffer@5.7.1: + resolution: + { + integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, + } + + bundle-name@4.1.0: + resolution: + { + integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==, + } + engines: { node: ">=18" } + + byte-counter@0.1.0: + resolution: + { + integrity: sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ==, + } + engines: { node: ">=20" } + + cacheable-lookup@7.0.0: + resolution: + { + integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==, + } + engines: { node: ">=14.16" } + + cacheable-request@13.0.18: + resolution: + { + integrity: sha512-rFWadDRKJs3s2eYdXlGggnBZKG7MTblkFBB0YllFds+UYnfogDp2wcR6JN97FhRkHTvq59n2vhNoHNZn29dh/Q==, + } + engines: { node: ">=18" } + + cacheable@2.3.2: + resolution: + { + integrity: sha512-w+ZuRNmex9c1TR9RcsxbfTKCjSL0rh1WA5SABbrWprIHeNBdmyQLSYonlDy9gpD+63XT8DgZ/wNh1Smvc9WnJA==, + } + + cachedir@2.3.0: + resolution: + { + integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==, + } + engines: { node: ">=6" } + + call-bind-apply-helpers@1.0.2: + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: ">= 0.4" } + + call-bind@1.0.8: + resolution: + { + integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, + } + engines: { node: ">= 0.4" } + + call-bound@1.0.4: + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: ">= 0.4" } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: ">=6" } + + camelcase-css@2.0.1: + resolution: + { + integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, + } + engines: { node: ">= 6" } + + camelcase@5.3.1: + resolution: + { + integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==, + } + engines: { node: ">=6" } + + caniuse-api@3.0.0: + resolution: + { + integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==, + } + + caniuse-lite@1.0.30001770: + resolution: + { + integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==, + } + + chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: ">=4" } + + chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: ">=10" } + + chalk@5.6.2: + resolution: + { + integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==, + } + engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 } + + char-regex@1.0.2: + resolution: + { + integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==, + } + engines: { node: ">=10" } + + chardet@0.7.0: + resolution: + { + integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==, + } + + choices.js@11.1.0: + resolution: + { + integrity: sha512-mIt0uLhedHg2ea/K2PACrVpt391vRGHuOoctPAiHcyemezwzNMxj7jOzNEk8e7EbjLh0S0sspDkSCADOKz9kcw==, + } + + chokidar@3.6.0: + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: ">= 8.10.0" } + + ci-info@4.4.0: + resolution: + { + integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==, + } + engines: { node: ">=8" } + + clean-stack@2.2.0: + resolution: + { + integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, + } + engines: { node: ">=6" } + + clean-stack@5.3.0: + resolution: + { + integrity: sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==, + } + engines: { node: ">=14.16" } + + cli-cursor@3.1.0: + resolution: + { + integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==, + } + engines: { node: ">=8" } + + cli-cursor@5.0.0: + resolution: + { + integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==, + } + engines: { node: ">=18" } + + cli-highlight@2.1.11: + resolution: + { + integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==, + } + engines: { node: ">=8.0.0", npm: ">=5.0.0" } + hasBin: true + + cli-spinners@2.9.2: + resolution: + { + integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==, + } + engines: { node: ">=6" } + + cli-table3@0.6.5: + resolution: + { + integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==, + } + engines: { node: 10.* || >= 12.* } + + cli-truncate@5.1.1: + resolution: + { + integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==, + } + engines: { node: ">=20" } + + cli-width@3.0.0: + resolution: + { + integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==, + } + engines: { node: ">= 10" } + + cliui@6.0.0: + resolution: + { + integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==, + } + + cliui@7.0.4: + resolution: + { + integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==, + } + + cliui@8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, + } + engines: { node: ">=12" } + + cliui@9.0.1: + resolution: + { + integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==, + } + engines: { node: ">=20" } + + clone@1.0.4: + resolution: + { + integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==, + } + engines: { node: ">=0.8" } + + codemirror@6.0.2: + resolution: + { + integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==, + } + + color-convert@1.9.3: + resolution: + { + integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, + } + + color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: ">=7.0.0" } + + color-name@1.1.3: + resolution: + { + integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, + } + + color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + colord@2.9.3: + resolution: + { + integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==, + } + + colorette@2.0.20: + resolution: + { + integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, + } + + commander@11.1.0: + resolution: + { + integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==, + } + engines: { node: ">=16" } + + commander@14.0.3: + resolution: + { + integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==, + } + engines: { node: ">=20" } + + commander@2.20.3: + resolution: + { + integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, + } + + commander@4.1.1: + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: ">= 6" } + + commander@7.2.0: + resolution: + { + integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==, + } + engines: { node: ">= 10" } + + commitizen@4.3.1: + resolution: + { + integrity: sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==, + } + engines: { node: ">= 12" } + hasBin: true + + common-tags@1.8.2: + resolution: + { + integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==, + } + engines: { node: ">=4.0.0" } + + compare-func@2.0.0: + resolution: + { + integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==, + } + + concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + config-chain@1.1.13: + resolution: + { + integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==, + } + + conventional-changelog-angular@8.1.0: + resolution: + { + integrity: sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==, + } + engines: { node: ">=18" } + + conventional-changelog-conventionalcommits@9.1.0: + resolution: + { + integrity: sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==, + } + engines: { node: ">=18" } + + conventional-changelog-writer@8.2.0: + resolution: + { + integrity: sha512-Y2aW4596l9AEvFJRwFGJGiQjt2sBYTjPD18DdvxX9Vpz0Z7HQ+g1Z+6iYDAm1vR3QOJrDBkRHixHK/+FhkR6Pw==, + } + engines: { node: ">=18" } + hasBin: true + + conventional-commit-types@3.0.0: + resolution: + { + integrity: sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==, + } + + conventional-commits-filter@5.0.0: + resolution: + { + integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==, + } + engines: { node: ">=18" } + + conventional-commits-parser@6.2.1: + resolution: + { + integrity: sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==, + } + engines: { node: ">=18" } + hasBin: true + + convert-hrtime@5.0.0: + resolution: + { + integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==, + } + engines: { node: ">=12" } + + convert-source-map@2.0.0: + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } + + core-js-compat@3.48.0: + resolution: + { + integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==, + } + + core-js@3.48.0: + resolution: + { + integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==, + } + + core-util-is@1.0.3: + resolution: + { + integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, + } + + cosmiconfig-typescript-loader@6.2.0: + resolution: + { + integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==, + } + engines: { node: ">=v18" } + peerDependencies: + "@types/node": "*" + cosmiconfig: ">=9" + typescript: ">=5" + + cosmiconfig@9.0.0: + resolution: + { + integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==, + } + engines: { node: ">=14" } + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + + crelt@1.0.6: + resolution: + { + integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==, + } + + cross-env@10.1.0: + resolution: + { + integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==, + } + engines: { node: ">=20" } + hasBin: true + + cross-spawn@7.0.6: + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: ">= 8" } + + crypto-js@4.2.0: + resolution: + { + integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==, + } + + crypto-random-string@2.0.0: + resolution: + { + integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==, + } + engines: { node: ">=8" } + + crypto-random-string@4.0.0: + resolution: + { + integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==, + } + engines: { node: ">=12" } + + css-blank-pseudo@8.0.1: + resolution: + { + integrity: sha512-C5B2e5hCM4llrQkUms+KnWEMVW8K1n2XvX9G7ppfMZJQ7KAS/4rNnkP1Cs+HhWriOz1mWWTMFD4j1J7s31Dgug==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + css-declaration-sorter@7.3.1: + resolution: + { + integrity: sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==, + } + engines: { node: ^14 || ^16 || >=18 } + peerDependencies: + postcss: ^8.0.9 + + css-functions-list@3.3.3: + resolution: + { + integrity: sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==, + } + engines: { node: ">=12" } + + css-has-pseudo@8.0.0: + resolution: + { + integrity: sha512-Uz/bsHRbOeir/5Oeuz85tq/yLJLxX+3dpoRdjNTshs6jjqwUg8XaEZGDd0ci3fw7l53Srw0EkJ8mYan0eW5uGQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + css-prefers-color-scheme@11.0.0: + resolution: + { + integrity: sha512-fv0mgtwUhh2m9iio3Kxc2CkrogjIaRdMFaaqyzSFdii17JF4cfPyMNX72B15ZW2Nrr/NZUpxI4dec1VMHYJvdw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + css-select@5.2.2: + resolution: + { + integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==, + } + + css-tree@2.2.1: + resolution: + { + integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + + css-tree@3.1.0: + resolution: + { + integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 } + + css-what@6.2.2: + resolution: + { + integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==, + } + engines: { node: ">= 6" } + + cssdb@8.7.1: + resolution: + { + integrity: sha512-+F6LKx48RrdGOtE4DT5jz7Uo+VeyKXpK797FAevIkzjV8bMHz6xTO5F7gNDcRCHmPgD5jj2g6QCsY9zmVrh38A==, + } + + cssesc@3.0.0: + resolution: + { + integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, + } + engines: { node: ">=4" } + hasBin: true + + cssnano-preset-default@7.0.10: + resolution: + { + integrity: sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + cssnano-utils@5.0.1: + resolution: + { + integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + cssnano@7.1.2: + resolution: + { + integrity: sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + csso@5.0.5: + resolution: + { + integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==, + } + engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" } + + cz-conventional-changelog@3.3.0: + resolution: + { + integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==, + } + engines: { node: ">= 10" } + + d3-array@3.2.4: + resolution: + { + integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==, + } + engines: { node: ">=12" } + + d3-color@3.1.0: + resolution: + { + integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==, + } + engines: { node: ">=12" } + + d3-dispatch@3.0.1: + resolution: + { + integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==, + } + engines: { node: ">=12" } + + d3-ease@3.0.1: + resolution: + { + integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==, + } + engines: { node: ">=12" } + + d3-force@3.0.0: + resolution: + { + integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==, + } + engines: { node: ">=12" } + + d3-geo-projection@4.0.0: + resolution: + { + integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==, + } + engines: { node: ">=12" } + hasBin: true + + d3-geo@3.1.1: + resolution: + { + integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==, + } + engines: { node: ">=12" } + + d3-interpolate@3.0.1: + resolution: + { + integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==, + } + engines: { node: ">=12" } + + d3-quadtree@3.0.1: + resolution: + { + integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==, + } + engines: { node: ">=12" } + + d3-selection@3.0.0: + resolution: + { + integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==, + } + engines: { node: ">=12" } + + d3-timer@3.0.1: + resolution: + { + integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==, + } + engines: { node: ">=12" } + + d3-transition@3.0.1: + resolution: + { + integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==, + } + engines: { node: ">=12" } + peerDependencies: + d3-selection: 2 - 3 + + dargs@8.1.0: + resolution: + { + integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==, + } + engines: { node: ">=12" } + + data-view-buffer@1.0.2: + resolution: + { + integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, + } + engines: { node: ">= 0.4" } + + data-view-byte-length@1.0.2: + resolution: + { + integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, + } + engines: { node: ">= 0.4" } + + data-view-byte-offset@1.0.1: + resolution: + { + integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, + } + engines: { node: ">= 0.4" } + + debug@4.4.3: + resolution: + { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: ">=6.0" } + peerDependencies: + supports-color: "*" + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: + { + integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==, + } + engines: { node: ">=0.10.0" } + + decompress-response@10.0.0: + resolution: + { + integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==, + } + engines: { node: ">=20" } + + dedent@0.7.0: + resolution: + { + integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==, + } + + deep-equal@1.1.2: + resolution: + { + integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==, + } + engines: { node: ">= 0.4" } + + deep-extend@0.6.0: + resolution: + { + integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, + } + engines: { node: ">=4.0.0" } + + deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + deepmerge@4.3.1: + resolution: + { + integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, + } + engines: { node: ">=0.10.0" } + + default-browser-id@5.0.1: + resolution: + { + integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==, + } + engines: { node: ">=18" } + + default-browser@5.5.0: + resolution: + { + integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==, + } + engines: { node: ">=18" } + + defaults@1.0.4: + resolution: + { + integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==, + } + + define-data-property@1.1.4: + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: ">= 0.4" } + + define-lazy-prop@3.0.0: + resolution: + { + integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==, + } + engines: { node: ">=12" } + + define-properties@1.2.1: + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: ">= 0.4" } + + detect-file@1.0.0: + resolution: + { + integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==, + } + engines: { node: ">=0.10.0" } + + detect-indent@6.1.0: + resolution: + { + integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==, + } + engines: { node: ">=8" } + + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: ">=8" } + + dfa@1.2.0: + resolution: + { + integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==, + } + + didyoumean@1.2.2: + resolution: + { + integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, + } + + dir-glob@3.0.1: + resolution: + { + integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, + } + engines: { node: ">=8" } + + dlv@1.1.3: + resolution: + { + integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, + } + + dom-serializer@2.0.0: + resolution: + { + integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, + } + + domelementtype@2.3.0: + resolution: + { + integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==, + } + + domhandler@5.0.3: + resolution: + { + integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, + } + engines: { node: ">= 4" } + + domutils@3.2.2: + resolution: + { + integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==, + } + + dot-prop@5.3.0: + resolution: + { + integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==, + } + engines: { node: ">=8" } + + dunder-proto@1.0.1: + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: ">= 0.4" } + + duplexer2@0.1.4: + resolution: + { + integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==, + } + + ejs@3.1.10: + resolution: + { + integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==, + } + engines: { node: ">=0.10.0" } + hasBin: true + + electron-to-chromium@1.5.286: + resolution: + { + integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==, + } + + emoji-regex@10.6.0: + resolution: + { + integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==, + } + + emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + + emojilib@2.4.0: + resolution: + { + integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==, + } + + entities@4.5.0: + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: ">=0.12" } + + env-ci@11.2.0: + resolution: + { + integrity: sha512-D5kWfzkmaOQDioPmiviWAVtKmpPT4/iJmMVQxWxMPJTFyTkdc5JQUfc5iXEeWxcOdsYTKSAiA/Age4NUOqKsRA==, + } + engines: { node: ^18.17 || >=20.6.1 } + + env-paths@2.2.1: + resolution: + { + integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, + } + engines: { node: ">=6" } + + environment@1.1.0: + resolution: + { + integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==, + } + engines: { node: ">=18" } + + error-ex@1.3.4: + resolution: + { + integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==, + } + + error-stack-parser-es@1.0.5: + resolution: + { + integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==, + } + + es-abstract@1.24.1: + resolution: + { + integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==, + } + engines: { node: ">= 0.4" } + + es-define-property@1.0.1: + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: ">= 0.4" } + + es-errors@1.3.0: + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: ">= 0.4" } + + es-object-atoms@1.1.1: + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: ">= 0.4" } + + es-set-tostringtag@2.1.0: + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: ">= 0.4" } + + es-to-primitive@1.3.0: + resolution: + { + integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, + } + engines: { node: ">= 0.4" } + + esbuild@0.27.3: + resolution: + { + integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==, + } + engines: { node: ">=18" } + hasBin: true + + escalade@3.2.0: + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: ">=6" } + + escape-string-regexp@1.0.5: + resolution: + { + integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, + } + engines: { node: ">=0.8.0" } + + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: ">=10" } + + escape-string-regexp@5.0.0: + resolution: + { + integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==, + } + engines: { node: ">=12" } + + eslint-config-prettier@10.1.8: + resolution: + { + integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==, + } + hasBin: true + peerDependencies: + eslint: ">=7.0.0" + + eslint-plugin-prettier@5.5.5: + resolution: + { + integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + 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 + + eslint-scope@9.1.0: + resolution: + { + integrity: sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + eslint-visitor-keys@3.4.3: + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@4.2.1: + resolution: + { + integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint-visitor-keys@5.0.0: + resolution: + { + integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + eslint@10.0.0: + resolution: + { + integrity: sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + hasBin: true + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: + { + integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + espree@11.1.0: + resolution: + { + integrity: sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==, + } + engines: { node: ^20.19.0 || ^22.13.0 || >=24 } + + esquery@1.7.0: + resolution: + { + integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==, + } + engines: { node: ">=0.10" } + + esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: ">=4.0" } + + estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: ">=4.0" } + + estree-walker@1.0.1: + resolution: + { + integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==, + } + + estree-walker@2.0.2: + resolution: + { + integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, + } + + esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: ">=0.10.0" } + + eventemitter3@5.0.4: + resolution: + { + integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==, + } + + execa@5.1.1: + resolution: + { + integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, + } + engines: { node: ">=10" } + + execa@8.0.1: + resolution: + { + integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==, + } + engines: { node: ">=16.17" } + + execa@9.6.1: + resolution: + { + integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==, + } + engines: { node: ^18.19.0 || >=20.5.0 } + + expand-tilde@2.0.2: + resolution: + { + integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==, + } + engines: { node: ">=0.10.0" } + + external-editor@3.1.0: + resolution: + { + integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==, + } + engines: { node: ">=4" } + + fast-content-type-parse@3.0.0: + resolution: + { + integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==, + } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-diff@1.3.0: + resolution: + { + integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==, + } + + fast-glob@3.3.3: + resolution: + { + integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, + } + engines: { node: ">=8.6.0" } + + fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fast-uri@3.1.0: + resolution: + { + integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==, + } + + fastest-levenshtein@1.0.16: + resolution: + { + integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==, + } + engines: { node: ">= 4.9.1" } + + fastq@1.20.1: + resolution: + { + integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==, + } + + fdir@6.5.0: + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: ">=12.0.0" } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + figures@2.0.0: + resolution: + { + integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==, + } + engines: { node: ">=4" } + + figures@3.2.0: + resolution: + { + integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==, + } + engines: { node: ">=8" } + + figures@6.1.0: + resolution: + { + integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==, + } + engines: { node: ">=18" } + + file-entry-cache@11.1.2: + resolution: + { + integrity: sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log==, + } + + file-entry-cache@8.0.0: + resolution: + { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: ">=16.0.0" } + + filelist@1.0.4: + resolution: + { + integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==, + } + + fill-range@7.1.1: + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: ">=8" } + + find-node-modules@2.1.3: + resolution: + { + integrity: sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==, + } + + find-root@1.1.0: + resolution: + { + integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, + } + + find-up-simple@1.0.1: + resolution: + { + integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==, + } + engines: { node: ">=18" } + + find-up@2.1.0: + resolution: + { + integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==, + } + engines: { node: ">=4" } + + find-up@4.1.0: + resolution: + { + integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, + } + engines: { node: ">=8" } + + find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: ">=10" } + + find-versions@6.0.0: + resolution: + { + integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==, + } + engines: { node: ">=18" } + + findup-sync@4.0.0: + resolution: + { + integrity: sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==, + } + engines: { node: ">= 8" } + + flat-cache@4.0.1: + resolution: + { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: ">=16" } + + flat-cache@6.1.20: + resolution: + { + integrity: sha512-AhHYqwvN62NVLp4lObVXGVluiABTHapoB57EyegZVmazN+hhGhLTn3uZbOofoTw4DSDvVCadzzyChXhOAvy8uQ==, + } + + flatpickr@4.6.13: + resolution: + { + integrity: sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==, + } + + flatted@3.3.3: + resolution: + { + integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, + } + + for-each@0.3.5: + resolution: + { + integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, + } + engines: { node: ">= 0.4" } + + foreground-child@3.3.1: + resolution: + { + integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, + } + engines: { node: ">=14" } + + form-data-encoder@4.1.0: + resolution: + { + integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==, + } + engines: { node: ">= 18" } + + formdata-node@6.0.3: + resolution: + { + integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==, + } + engines: { node: ">= 18" } + + fraction.js@5.3.4: + resolution: + { + integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==, + } + + from2@2.3.0: + resolution: + { + integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==, + } + + fs-extra@11.3.3: + resolution: + { + integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==, + } + engines: { node: ">=14.14" } + + fs-extra@9.1.0: + resolution: + { + integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==, + } + engines: { node: ">=10" } + + fs.realpath@1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } + + fscreen@1.2.0: + resolution: + { + integrity: sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg==, + } + + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + + function-bind@1.1.2: + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } + + function-timeout@1.0.2: + resolution: + { + integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==, + } + engines: { node: ">=18" } + + function.prototype.name@1.1.8: + resolution: + { + integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, + } + engines: { node: ">= 0.4" } + + functions-have-names@1.2.3: + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } + + fuse.js@7.1.0: + resolution: + { + integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==, + } + engines: { node: ">=10" } + + generator-function@2.0.1: + resolution: + { + integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==, + } + engines: { node: ">= 0.4" } + + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: ">=6.9.0" } + + get-caller-file@2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } + + get-east-asian-width@1.5.0: + resolution: + { + integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==, + } + engines: { node: ">=18" } + + get-intrinsic@1.3.0: + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: ">= 0.4" } + + get-own-enumerable-property-symbols@3.0.2: + resolution: + { + integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==, + } + + get-proto@1.0.1: + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: ">= 0.4" } + + get-stream@6.0.1: + resolution: + { + integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, + } + engines: { node: ">=10" } + + get-stream@7.0.1: + resolution: + { + integrity: sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==, + } + engines: { node: ">=16" } + + get-stream@8.0.1: + resolution: + { + integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==, + } + engines: { node: ">=16" } + + get-stream@9.0.1: + resolution: + { + integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==, + } + engines: { node: ">=18" } + + get-symbol-description@1.1.0: + resolution: + { + integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, + } + engines: { node: ">= 0.4" } + + git-log-parser@1.2.1: + resolution: + { + integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==, + } + + git-raw-commits@4.0.0: + resolution: + { + integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==, + } + engines: { node: ">=16" } + hasBin: true + + glob-parent@5.1.2: + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: ">= 6" } + + glob-parent@6.0.2: + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: ">=10.13.0" } + + glob@11.1.0: + resolution: + { + integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==, + } + engines: { node: 20 || >=22 } + 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 + hasBin: true + + glob@13.0.5: + resolution: + { + integrity: sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw==, + } + engines: { node: 20 || >=22 } + + glob@7.2.3: + resolution: + { + 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 + + global-directory@4.0.1: + resolution: + { + integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==, + } + engines: { node: ">=18" } + + global-modules@1.0.0: + resolution: + { + integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==, + } + engines: { node: ">=0.10.0" } + + global-modules@2.0.0: + resolution: + { + integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==, + } + engines: { node: ">=6" } + + global-prefix@1.0.2: + resolution: + { + integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==, + } + engines: { node: ">=0.10.0" } + + global-prefix@3.0.0: + resolution: + { + integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==, + } + engines: { node: ">=6" } + + globals@14.0.0: + resolution: + { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: ">=18" } + + globals@17.3.0: + resolution: + { + integrity: sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==, + } + engines: { node: ">=18" } + + globalthis@1.0.4: + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: ">= 0.4" } + + globby@14.1.0: + resolution: + { + integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==, + } + engines: { node: ">=18" } + + globby@16.1.1: + resolution: + { + integrity: sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==, + } + engines: { node: ">=20" } + + globjoin@0.1.4: + resolution: + { + integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==, + } + + gopd@1.2.0: + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: ">= 0.4" } + + got@14.6.6: + resolution: + { + integrity: sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==, + } + engines: { node: ">=20" } + + graceful-fs@4.2.10: + resolution: + { + integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, + } + + graceful-fs@4.2.11: + resolution: + { + integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, + } + + handlebars@4.7.8: + resolution: + { + integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==, + } + engines: { node: ">=0.4.7" } + hasBin: true + + has-bigints@1.1.0: + resolution: + { + integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, + } + engines: { node: ">= 0.4" } + + has-flag@3.0.0: + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: ">=4" } + + has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: ">=8" } + + has-flag@5.0.1: + resolution: + { + integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==, + } + engines: { node: ">=12" } + + has-property-descriptors@1.0.2: + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } + + has-proto@1.2.0: + resolution: + { + integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, + } + engines: { node: ">= 0.4" } + + has-symbols@1.1.0: + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: ">= 0.4" } + + has-tostringtag@1.0.2: + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: ">= 0.4" } + + hashery@1.5.0: + resolution: + { + integrity: sha512-nhQ6ExaOIqti2FDWoEMWARUqIKyjr2VcZzXShrI+A3zpeiuPWzx6iPftt44LhP74E5sW36B75N6VHbvRtpvO6Q==, + } + engines: { node: ">=20" } + + hasown@2.0.2: + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: ">= 0.4" } + + highlight.js@10.7.3: + resolution: + { + integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, + } + + homedir-polyfill@1.0.3: + resolution: + { + integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==, + } + engines: { node: ">=0.10.0" } + + hook-std@4.0.0: + resolution: + { + integrity: sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==, + } + engines: { node: ">=20" } + + hookified@1.15.1: + resolution: + { + integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==, + } + + hosted-git-info@7.0.2: + resolution: + { + integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==, + } + engines: { node: ^16.14.0 || >=18.0.0 } + + hosted-git-info@9.0.2: + resolution: + { + integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==, + } + engines: { node: ^20.17.0 || >=22.9.0 } + + hpagent@1.2.0: + resolution: + { + integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==, + } + engines: { node: ">=14" } + + html-tags@5.1.0: + resolution: + { + integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==, + } + engines: { node: ">=20.10" } + + htmlfy@1.0.1: + resolution: + { + integrity: sha512-M85PmyEpWUDqhlEknsnvqmqGLq67h8e86WuKLMdXQdUl8iyvOSDbAAyv0tv0IVmIfh7Py1Vsot/IU1skdswt6g==, + } + + http-cache-semantics@4.2.0: + resolution: + { + integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, + } + + http-proxy-agent@7.0.2: + resolution: + { + integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, + } + engines: { node: ">= 14" } + + http2-wrapper@2.2.1: + resolution: + { + integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==, + } + engines: { node: ">=10.19.0" } + + https-proxy-agent@7.0.6: + resolution: + { + integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, + } + engines: { node: ">= 14" } + + human-signals@2.1.0: + resolution: + { + integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, + } + engines: { node: ">=10.17.0" } + + human-signals@5.0.0: + resolution: + { + integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==, + } + engines: { node: ">=16.17.0" } + + human-signals@8.0.1: + resolution: + { + integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==, + } + engines: { node: ">=18.18.0" } + + husky@9.1.7: + resolution: + { + integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==, + } + engines: { node: ">=18" } + hasBin: true + + iconv-lite@0.4.24: + resolution: + { + integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, + } + engines: { node: ">=0.10.0" } + + iconv-lite@0.7.2: + resolution: + { + integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==, + } + engines: { node: ">=0.10.0" } + + idb@7.1.1: + resolution: + { + integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==, + } + + ieee754@1.2.1: + resolution: + { + integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, + } + + ignore@5.3.2: + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: ">= 4" } + + ignore@7.0.5: + resolution: + { + integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, + } + engines: { node: ">= 4" } + + import-fresh@3.3.1: + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: ">=6" } + + import-from-esm@2.0.0: + resolution: + { + integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==, + } + engines: { node: ">=18.20" } + + import-meta-resolve@4.2.0: + resolution: + { + integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==, + } + + imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: ">=0.8.19" } + + indent-string@4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: ">=8" } + + indent-string@5.0.0: + resolution: + { + integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==, + } + engines: { node: ">=12" } + + index-to-position@1.2.0: + resolution: + { + integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==, + } + engines: { node: ">=18" } + + inflight@1.0.6: + resolution: + { + 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. + + inherits@2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } + + ini@1.3.8: + resolution: + { + integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, + } + + ini@4.1.1: + resolution: + { + integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==, + } + engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 } + + inquirer@7.3.3: + resolution: + { + integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==, + } + engines: { node: ">=8.0.0" } + + inquirer@8.2.5: + resolution: + { + integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==, + } + engines: { node: ">=12.0.0" } + + internal-slot@1.1.0: + resolution: + { + integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, + } + engines: { node: ">= 0.4" } + + internmap@2.0.3: + resolution: + { + integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==, + } + engines: { node: ">=12" } + + into-stream@7.0.0: + resolution: + { + integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==, + } + engines: { node: ">=12" } + + is-arguments@1.2.0: + resolution: + { + integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==, + } + engines: { node: ">= 0.4" } + + is-array-buffer@3.0.5: + resolution: + { + integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, + } + engines: { node: ">= 0.4" } + + is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + + is-async-function@2.1.1: + resolution: + { + integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, + } + engines: { node: ">= 0.4" } + + is-bigint@1.1.0: + resolution: + { + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, + } + engines: { node: ">= 0.4" } + + is-binary-path@2.1.0: + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: ">=8" } + + is-boolean-object@1.2.2: + resolution: + { + integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, + } + engines: { node: ">= 0.4" } + + is-callable@1.2.7: + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: ">= 0.4" } + + is-ci@4.1.0: + resolution: + { + integrity: sha512-Ab9bQDQ11lWootZUI5qxgN2ZXwxNI5hTwnsvOc1wyxQ7zQ8OkEDw79mI0+9jI3x432NfwbVRru+3noJfXF6lSQ==, + } + hasBin: true + + is-core-module@2.16.1: + resolution: + { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: ">= 0.4" } + + is-data-view@1.0.2: + resolution: + { + integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, + } + engines: { node: ">= 0.4" } + + is-date-object@1.1.0: + resolution: + { + integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, + } + engines: { node: ">= 0.4" } + + is-docker@3.0.0: + resolution: + { + integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + hasBin: true + + is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: ">=0.10.0" } + + is-finalizationregistry@1.1.1: + resolution: + { + integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, + } + engines: { node: ">= 0.4" } + + is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: ">=8" } + + is-fullwidth-code-point@5.1.0: + resolution: + { + integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==, + } + engines: { node: ">=18" } + + is-generator-function@1.1.2: + resolution: + { + integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==, + } + engines: { node: ">= 0.4" } + + is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: ">=0.10.0" } + + is-inside-container@1.0.0: + resolution: + { + integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==, + } + engines: { node: ">=14.16" } + hasBin: true + + is-interactive@1.0.0: + resolution: + { + integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==, + } + engines: { node: ">=8" } + + is-map@2.0.3: + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: ">= 0.4" } + + is-module@1.0.0: + resolution: + { + integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==, + } + + is-negative-zero@2.0.3: + resolution: + { + integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==, + } + engines: { node: ">= 0.4" } + + is-number-object@1.1.1: + resolution: + { + integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, + } + engines: { node: ">= 0.4" } + + is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: ">=0.12.0" } + + is-obj@1.0.1: + resolution: + { + integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==, + } + engines: { node: ">=0.10.0" } + + is-obj@2.0.0: + resolution: + { + integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==, + } + engines: { node: ">=8" } + + is-path-inside@4.0.0: + resolution: + { + integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==, + } + engines: { node: ">=12" } + + is-plain-obj@4.1.0: + resolution: + { + integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==, + } + engines: { node: ">=12" } + + is-plain-object@5.0.0: + resolution: + { + integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==, + } + engines: { node: ">=0.10.0" } + + is-regex@1.2.1: + resolution: + { + integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, + } + engines: { node: ">= 0.4" } + + is-regexp@1.0.0: + resolution: + { + integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==, + } + engines: { node: ">=0.10.0" } + + is-set@2.0.3: + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: ">= 0.4" } + + is-shared-array-buffer@1.0.4: + resolution: + { + integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, + } + engines: { node: ">= 0.4" } + + is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: ">=8" } + + is-stream@3.0.0: + resolution: + { + integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + is-stream@4.0.1: + resolution: + { + integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==, + } + engines: { node: ">=18" } + + is-string@1.1.1: + resolution: + { + integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, + } + engines: { node: ">= 0.4" } + + is-symbol@1.1.1: + resolution: + { + integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, + } + engines: { node: ">= 0.4" } + + is-typed-array@1.1.15: + resolution: + { + integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, + } + engines: { node: ">= 0.4" } + + is-unicode-supported@0.1.0: + resolution: + { + integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==, + } + engines: { node: ">=10" } + + is-unicode-supported@2.1.0: + resolution: + { + integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==, + } + engines: { node: ">=18" } + + is-utf8@0.2.1: + resolution: + { + integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==, + } + + is-weakmap@2.0.2: + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: ">= 0.4" } + + is-weakref@1.1.1: + resolution: + { + integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, + } + engines: { node: ">= 0.4" } + + is-weakset@2.0.4: + resolution: + { + integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, + } + engines: { node: ">= 0.4" } + + is-windows@1.0.2: + resolution: + { + integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==, + } + engines: { node: ">=0.10.0" } + + is-wsl@3.1.1: + resolution: + { + integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==, + } + engines: { node: ">=16" } + + isarray@1.0.0: + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } + + isarray@2.0.5: + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + issue-parser@7.0.1: + resolution: + { + integrity: sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==, + } + engines: { node: ^18.17 || >=20.6.1 } + + jackspeak@4.2.3: + resolution: + { + integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==, + } + engines: { node: 20 || >=22 } + + jake@10.9.4: + resolution: + { + integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==, + } + engines: { node: ">=10" } + hasBin: true + + java-properties@1.0.2: + resolution: + { + integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==, + } + engines: { node: ">= 0.6.0" } + + jiti@1.21.7: + resolution: + { + integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==, + } + hasBin: true + + jiti@2.6.1: + resolution: + { + integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==, + } + hasBin: true + + jpeg-exif@1.1.4: + resolution: + { + integrity: sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==, + } + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@4.1.1: + resolution: + { + integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==, + } + hasBin: true + + jsesc@3.1.0: + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: ">=6" } + hasBin: true + + json-buffer@3.0.1: + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } + + json-fixer@1.6.15: + resolution: + { + integrity: sha512-TuDuZ5KrgyjoCIppdPXBMqiGfota55+odM+j2cQ5rt/XKyKmqGB3Whz1F8SN8+60yYGy/Nu5lbRZ+rx8kBIvBw==, + } + engines: { node: ">=10" } + + json-parse-better-errors@1.0.2: + resolution: + { + integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==, + } + + json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + + json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + + json-schema-traverse@1.0.0: + resolution: + { + integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, + } + + json-schema@0.4.0: + resolution: + { + integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, + } + + json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + json5@2.2.3: + resolution: + { + integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, + } + engines: { node: ">=6" } + hasBin: true + + jsonfile@6.2.0: + resolution: + { + integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==, + } + + jsonpointer@5.0.1: + resolution: + { + integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==, + } + engines: { node: ">=0.10.0" } + + keyv@4.5.4: + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } + + keyv@5.6.0: + resolution: + { + integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==, + } + + kind-of@6.0.3: + resolution: + { + integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==, + } + engines: { node: ">=0.10.0" } + + known-css-properties@0.37.0: + resolution: + { + integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==, + } + + leaflet.markercluster@1.5.3: + resolution: + { + integrity: sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==, + } + peerDependencies: + leaflet: ^1.3.1 + + leaflet@1.9.4: + resolution: + { + integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==, + } + + leven@3.1.0: + resolution: + { + integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, + } + engines: { node: ">=6" } + + levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: ">= 0.8.0" } + + lilconfig@3.1.3: + resolution: + { + integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==, + } + engines: { node: ">=14" } + + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + + lint-staged@16.2.7: + resolution: + { + integrity: sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==, + } + engines: { node: ">=20.17" } + hasBin: true + + listr2@9.0.5: + resolution: + { + integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==, + } + engines: { node: ">=20.0.0" } + + lit-element@4.2.2: + resolution: + { + integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==, + } + + lit-html@3.3.2: + resolution: + { + integrity: sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw==, + } + + lit@3.3.2: + resolution: + { + integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==, + } + + load-json-file@4.0.0: + resolution: + { + integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==, + } + engines: { node: ">=4" } + + locate-path@2.0.0: + resolution: + { + integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==, + } + engines: { node: ">=4" } + + locate-path@5.0.0: + resolution: + { + integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, + } + engines: { node: ">=8" } + + locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: ">=10" } + + lodash-es@4.17.23: + resolution: + { + integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==, + } + + lodash.camelcase@4.3.0: + resolution: + { + integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==, + } + + lodash.capitalize@4.2.1: + resolution: + { + integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==, + } + + lodash.debounce@4.0.8: + resolution: + { + integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==, + } + + lodash.escaperegexp@4.1.2: + resolution: + { + integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==, + } + + lodash.isplainobject@4.0.6: + resolution: + { + integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, + } + + lodash.isstring@4.0.1: + resolution: + { + integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, + } + + lodash.kebabcase@4.1.1: + resolution: + { + integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==, + } + + lodash.map@4.6.0: + resolution: + { + integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==, + } + + lodash.memoize@4.1.2: + resolution: + { + integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==, + } + + lodash.mergewith@4.6.2: + resolution: + { + integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==, + } + + lodash.snakecase@4.1.1: + resolution: + { + integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==, + } + + lodash.sortby@4.7.0: + resolution: + { + integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==, + } + + lodash.startcase@4.4.0: + resolution: + { + integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==, + } + + lodash.truncate@4.4.2: + resolution: + { + integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==, + } + + lodash.uniq@4.5.0: + resolution: + { + integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==, + } + + lodash.uniqby@4.7.0: + resolution: + { + integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==, + } + + lodash.upperfirst@4.3.1: + resolution: + { + integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==, + } + + lodash@4.17.21: + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, + } + + lodash@4.17.23: + resolution: + { + integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==, + } + + log-symbols@4.1.0: + resolution: + { + integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==, + } + engines: { node: ">=10" } + + log-update@6.1.0: + resolution: + { + integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==, + } + engines: { node: ">=18" } + + longest@2.0.1: + resolution: + { + integrity: sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==, + } + engines: { node: ">=0.10.0" } + + lowercase-keys@3.0.0: + resolution: + { + integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + lru-cache@10.4.3: + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } + + lru-cache@11.2.6: + resolution: + { + integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==, + } + engines: { node: 20 || >=22 } + + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + + magic-string@0.25.9: + resolution: + { + integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==, + } + + make-asynchronous@1.0.1: + resolution: + { + integrity: sha512-T9BPOmEOhp6SmV25SwLVcHK4E6JyG/coH3C6F1NjNXSziv/fd4GmsqMk8YR6qpPOswfaOCApSNkZv6fxoaYFcQ==, + } + engines: { node: ">=18" } + + marked-terminal@7.3.0: + resolution: + { + integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==, + } + engines: { node: ">=16.0.0" } + peerDependencies: + marked: ">=1 <16" + + marked@15.0.12: + resolution: + { + integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==, + } + engines: { node: ">= 18" } + hasBin: true + + marked@17.0.3: + resolution: + { + integrity: sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==, + } + engines: { node: ">= 20" } + hasBin: true + + math-intrinsics@1.1.0: + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: ">= 0.4" } + + mathml-tag-names@4.0.0: + resolution: + { + integrity: sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==, + } + + mdn-data@2.0.28: + resolution: + { + integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==, + } + + mdn-data@2.12.2: + resolution: + { + integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==, + } + + meow@12.1.1: + resolution: + { + integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==, + } + engines: { node: ">=16.10" } + + meow@13.2.0: + resolution: + { + integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==, + } + engines: { node: ">=18" } + + meow@14.0.0: + resolution: + { + integrity: sha512-JhC3R1f6dbspVtmF3vKjAWz1EVIvwFrGGPLSdU6rK79xBwHWTuHoLnRX/t1/zHS1Ch1Y2UtIrih7DAHuH9JFJA==, + } + engines: { node: ">=20" } + + merge-stream@2.0.0: + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } + + merge2@1.4.1: + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: ">= 8" } + + merge@2.1.1: + resolution: + { + integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==, + } + + micromatch@4.0.8: + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: ">=8.6" } + + mime@4.1.0: + resolution: + { + integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==, + } + engines: { node: ">=16" } + hasBin: true + + mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: ">=6" } + + mimic-fn@4.0.0: + resolution: + { + integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==, + } + engines: { node: ">=12" } + + mimic-function@5.0.1: + resolution: + { + integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==, + } + engines: { node: ">=18" } + + mimic-response@4.0.0: + resolution: + { + integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + mini-svg-data-uri@1.4.4: + resolution: + { + integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==, + } + hasBin: true + + minimatch@10.2.1: + resolution: + { + integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==, + } + engines: { node: 20 || >=22 } + + minimatch@3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } + + minimatch@5.1.6: + resolution: + { + integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, + } + engines: { node: ">=10" } + + minimatch@9.0.5: + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: ">=16 || 14 >=14.17" } + + minimist@1.2.7: + resolution: + { + integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==, + } + + minimist@1.2.8: + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } + + minipass@7.1.3: + resolution: + { + integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==, + } + engines: { node: ">=16 || 14 >=14.17" } + + mitt@3.0.1: + resolution: + { + integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==, + } + + mrmime@2.0.1: + resolution: + { + integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==, + } + engines: { node: ">=10" } + + ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + mute-stream@0.0.8: + resolution: + { + integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==, + } + + mz@2.7.0: + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } + + nano-spawn@2.0.0: + resolution: + { + integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==, + } + engines: { node: ">=20.17" } + + nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + + natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + + neo-async@2.6.2: + resolution: + { + integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==, + } + + nerf-dart@1.0.0: + resolution: + { + integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==, + } + + node-emoji@2.2.0: + resolution: + { + integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==, + } + engines: { node: ">=18" } + + node-fetch@2.7.0: + resolution: + { + integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==, + } + engines: { node: 4.x || >=6.0.0 } + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-releases@2.0.27: + resolution: + { + integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==, + } + + normalize-package-data@6.0.2: + resolution: + { + integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==, + } + engines: { node: ^16.14.0 || >=18.0.0 } + + normalize-package-data@8.0.0: + resolution: + { + integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==, + } + engines: { node: ^20.17.0 || >=22.9.0 } + + normalize-path@3.0.0: + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: ">=0.10.0" } + + normalize-url@8.1.1: + resolution: + { + integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==, + } + engines: { node: ">=14.16" } + + npm-run-path@4.0.1: + resolution: + { + integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, + } + engines: { node: ">=8" } + + npm-run-path@5.3.0: + resolution: + { + integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + npm-run-path@6.0.0: + resolution: + { + integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==, + } + engines: { node: ">=18" } + + npm@11.10.0: + resolution: + { + integrity: sha512-i8hE43iSIAMFuYVi8TxsEISdELM4fIza600aLjJ0ankGPLqd0oTPKMJqAcO/QWm307MbSlWGzJcNZ0lGMQgHPA==, + } + engines: { node: ^20.17.0 || >=22.9.0 } + hasBin: true + bundledDependencies: + - "@isaacs/string-locale-compare" + - "@npmcli/arborist" + - "@npmcli/config" + - "@npmcli/fs" + - "@npmcli/map-workspaces" + - "@npmcli/metavuln-calculator" + - "@npmcli/package-json" + - "@npmcli/promise-spawn" + - "@npmcli/redact" + - "@npmcli/run-script" + - "@sigstore/tuf" + - abbrev + - archy + - cacache + - chalk + - ci-info + - cli-columns + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + + nth-check@2.1.1: + resolution: + { + integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==, + } + + object-assign@4.1.1: + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: ">=0.10.0" } + + object-hash@3.0.0: + resolution: + { + integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, + } + engines: { node: ">= 6" } + + object-inspect@1.13.4: + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: ">= 0.4" } + + object-is@1.1.6: + resolution: + { + integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==, + } + engines: { node: ">= 0.4" } + + object-keys@1.1.1: + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: ">= 0.4" } + + object.assign@4.1.7: + resolution: + { + integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, + } + engines: { node: ">= 0.4" } + + ohash@2.0.11: + resolution: + { + integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==, + } + + once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + + onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: ">=6" } + + onetime@6.0.0: + resolution: + { + integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==, + } + engines: { node: ">=12" } + + onetime@7.0.0: + resolution: + { + integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==, + } + engines: { node: ">=18" } + + open@10.2.0: + resolution: + { + integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==, + } + engines: { node: ">=18" } + + optionator@0.9.4: + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: ">= 0.8.0" } + + ora@5.4.1: + resolution: + { + integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==, + } + engines: { node: ">=10" } + + os-tmpdir@1.0.2: + resolution: + { + integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==, + } + engines: { node: ">=0.10.0" } + + own-keys@1.0.1: + resolution: + { + integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, + } + engines: { node: ">= 0.4" } + + p-cancelable@4.0.1: + resolution: + { + integrity: sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==, + } + engines: { node: ">=14.16" } + + p-each-series@3.0.0: + resolution: + { + integrity: sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==, + } + engines: { node: ">=12" } + + p-event@6.0.1: + resolution: + { + integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==, + } + engines: { node: ">=16.17" } + + p-filter@4.1.0: + resolution: + { + integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==, + } + engines: { node: ">=18" } + + p-is-promise@3.0.0: + resolution: + { + integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==, + } + engines: { node: ">=8" } + + p-limit@1.3.0: + resolution: + { + integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==, + } + engines: { node: ">=4" } + + p-limit@2.3.0: + resolution: + { + integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, + } + engines: { node: ">=6" } + + p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: ">=10" } + + p-locate@2.0.0: + resolution: + { + integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==, + } + engines: { node: ">=4" } + + p-locate@4.1.0: + resolution: + { + integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, + } + engines: { node: ">=8" } + + p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: ">=10" } + + p-map@7.0.4: + resolution: + { + integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==, + } + engines: { node: ">=18" } + + p-reduce@2.1.0: + resolution: + { + integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==, + } + engines: { node: ">=8" } + + p-reduce@3.0.0: + resolution: + { + integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==, + } + engines: { node: ">=12" } + + p-timeout@6.1.4: + resolution: + { + integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==, + } + engines: { node: ">=14.16" } + + p-try@1.0.0: + resolution: + { + integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==, + } + engines: { node: ">=4" } + + p-try@2.2.0: + resolution: + { + integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, + } + engines: { node: ">=6" } + + package-json-from-dist@1.0.1: + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } + + pako@0.2.9: + resolution: + { + integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==, + } + + parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: ">=6" } + + parse-json@4.0.0: + resolution: + { + integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==, + } + engines: { node: ">=4" } + + parse-json@5.2.0: + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: ">=8" } + + parse-json@8.3.0: + resolution: + { + integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==, + } + engines: { node: ">=18" } + + parse-ms@4.0.0: + resolution: + { + integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==, + } + engines: { node: ">=18" } + + parse-passwd@1.0.0: + resolution: + { + integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==, + } + engines: { node: ">=0.10.0" } + + parse-path@7.1.0: + resolution: + { + integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==, + } + + parse-url@10.0.3: + resolution: + { + integrity: sha512-RvldzLvNE0DtOO1loukZsYcHCzHVUnHe7GNyrKIkavp7fNWs5ueX3kUzY/hXS8uRqDWwtaRKDcAmLEVouPIxIw==, + } + engines: { node: ">=14.13.0" } + + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: + { + integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==, + } + + parse5@5.1.1: + resolution: + { + integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==, + } + + parse5@6.0.1: + resolution: + { + integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==, + } + + path-exists@3.0.0: + resolution: + { + integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==, + } + engines: { node: ">=4" } + + path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: ">=8" } + + path-is-absolute@1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: ">=0.10.0" } + + path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: ">=8" } + + path-key@4.0.0: + resolution: + { + integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==, + } + engines: { node: ">=12" } + + path-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + + path-scurry@2.0.1: + resolution: + { + integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==, + } + engines: { node: 20 || >=22 } + + path-type@4.0.0: + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: ">=8" } + + path-type@6.0.0: + resolution: + { + integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==, + } + engines: { node: ">=18" } + + pathe@2.0.3: + resolution: + { + integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, + } + + pdfmake@0.2.23: + resolution: + { + integrity: sha512-A/IksoKb/ikOZH1edSDJ/2zBbqJKDghD4+fXn3rT7quvCJDlsZMs3NmIB3eajLMMFU9Bd3bZPVvlUMXhvFI+bQ==, + } + engines: { node: ">=18" } + + pegjs@0.10.0: + resolution: + { + integrity: sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==, + } + engines: { node: ">=0.10" } + hasBin: true + + perfect-debounce@2.1.0: + resolution: + { + integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==, + } + + performance-now@2.1.0: + resolution: + { + integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, + } + + picocolors@1.1.1: + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } + + picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: ">=8.6" } + + picomatch@4.0.3: + resolution: + { + integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, + } + engines: { node: ">=12" } + + pidtree@0.6.0: + resolution: + { + integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==, + } + engines: { node: ">=0.10" } + hasBin: true + + pify@2.3.0: + resolution: + { + integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, + } + engines: { node: ">=0.10.0" } + + pify@3.0.0: + resolution: + { + integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==, + } + engines: { node: ">=4" } + + pify@5.0.0: + resolution: + { + integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==, + } + engines: { node: ">=10" } + + pirates@4.0.7: + resolution: + { + integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, + } + engines: { node: ">= 6" } + + pkg-conf@2.1.0: + resolution: + { + integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==, + } + engines: { node: ">=4" } + + png-js@1.0.0: + resolution: + { + integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==, + } + + polylabel@1.1.0: + resolution: + { + integrity: sha512-bxaGcA40sL3d6M4hH72Z4NdLqxpXRsCFk8AITYg6x1rn1Ei3izf00UMLklerBZTO49aPA3CYrIwVulx2Bce2pA==, + } + + possible-typed-array-names@1.1.0: + resolution: + { + integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, + } + engines: { node: ">= 0.4" } + + postcss-attribute-case-insensitive@8.0.0: + resolution: + { + integrity: sha512-fovIPEV35c2JzVXdmP+sp2xirbBMt54J+upU8u6TSj410kUU5+axgEzvBBSAX8KCybze8CFCelzFAw/FfWg2TA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-calc@10.1.1: + resolution: + { + integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==, + } + engines: { node: ^18.12 || ^20.9 || >=22.0 } + peerDependencies: + postcss: ^8.4.38 + + postcss-clamp@4.1.0: + resolution: + { + integrity: sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==, + } + engines: { node: ">=7.6.0" } + peerDependencies: + postcss: ^8.4.6 + + postcss-color-functional-notation@8.0.1: + resolution: + { + integrity: sha512-f1itLOG10iAa9mBAAtIHj/wfDs3srsNv/vrAsiRrIOfTCjhjxHxL1g06vvpQ86he2BP5HwB4cN72EZQ8rkegpA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-color-hex-alpha@11.0.0: + resolution: + { + integrity: sha512-NCGa6vjIyrjosz9GqRxVKbONBklz5TeipYqTJp3IqbnBWlBq5e5EMtG6MaX4vqk9LzocPfMQkuRK9tfk+OQuKg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-color-rebeccapurple@11.0.0: + resolution: + { + integrity: sha512-g9561mx7cbdqx7XeO/L+lJzVlzu7bICyXr72efBVKZGxIhvBBJf9fGXn3Cb6U4Bwh3LbzQO2e9NWBLVYdX5Eag==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-colormin@7.0.5: + resolution: + { + integrity: sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-convert-values@7.0.8: + resolution: + { + integrity: sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-custom-media@12.0.0: + resolution: + { + integrity: sha512-jIgEvqceN6ru2uQ0f75W1g+JDi0UyECFeJKjPG7UcSkW3+03LDKH2c6h+9C0XuDTV4y2pEHmD5AJtVBq1OGnZA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-custom-properties@15.0.0: + resolution: + { + integrity: sha512-FsD3VNtFr3qmspvIobDRszK9onKPHp8iHG4Aox2Nnm9SL93uw5GDw4z+NM7zWKiw6U+DSNm24JUm4coyIyanzQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-custom-selectors@9.0.0: + resolution: + { + integrity: sha512-VuV5tLPAm6wq1u699dsrhGCzfLobKe0eD3G8bw3BcTJt6wqQ7RQdfaveJVsCAi23OaQbjIi3K1C7Fj3yZH3f1g==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-dir-pseudo-class@10.0.0: + resolution: + { + integrity: sha512-DmtIzULpyC8XaH4b5AaUgt4Jic4QmrECqidNCdR7u7naQFdnxX80YI06u238a+ZVRXwURDxVzy0s/UQnWmpVeg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-discard-comments@7.0.5: + resolution: + { + integrity: sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-duplicates@7.0.2: + resolution: + { + integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: + { + integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-overridden@7.0.1: + resolution: + { + integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-double-position-gradients@7.0.0: + resolution: + { + integrity: sha512-Msr/dxj8Os7KLJE5Hdhvprwm3K5Zrh1KTY0eFN3ngPKNkej/Usy4BM9JQmqE6CLAkDpHoQVsi4snbL72CPt6qg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-focus-visible@11.0.0: + resolution: + { + integrity: sha512-VG1a9kBKizUBWS66t5xyB4uLONBnvZLCmZXxT40FALu8EF0QgVZBYy5ApC0KhmpHsv+pvHMJHB3agKHwmocWjw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-focus-within@10.0.0: + resolution: + { + integrity: sha512-dvql0fzUTG+gcJYp+KTbag5vAjuo94LDYZHkqDV1rnf5gPGer1v/SrmIZBdvKU8moep3HbcbujqGjzSb3DL53Q==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-font-variant@5.0.0: + resolution: + { + integrity: sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==, + } + peerDependencies: + postcss: ^8.1.0 + + postcss-gap-properties@7.0.0: + resolution: + { + integrity: sha512-PSDF2QoZMRUbsINvXObQgxx4HExRP85QTT8qS/YN9fBsCPWCqUuwqAD6E6PNp0BqL/jU1eyWUBORaOK/J/9LDA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-image-set-function@8.0.0: + resolution: + { + integrity: sha512-rEGNkOkNusf4+IuMmfEoIdLuVmvbExGbmG+MIsyV6jR5UaWSoyPcAYHV/PxzVDCmudyF+2Nh/o6Ub2saqUdnuA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-import@15.1.0: + resolution: + { + integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==, + } + engines: { node: ">=14.0.0" } + peerDependencies: + postcss: ^8.0.0 + + postcss-import@16.1.1: + resolution: + { + integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==, + } + engines: { node: ">=18.0.0" } + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: + { + integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==, + } + engines: { node: ^12 || ^14 || >= 16 } + peerDependencies: + postcss: ^8.4.21 + + postcss-lab-function@8.0.1: + resolution: + { + integrity: sha512-Q/ANnuCYtanAc+2NnCaZrYu+GofYQUV603JXL0KB6GlcXxpnm/UerPAmpKQdb9pxYUkpKovGxfL43aOUnpF/Hg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-load-config@6.0.1: + resolution: + { + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, + } + engines: { node: ">= 18" } + peerDependencies: + jiti: ">=1.21.0" + postcss: ">=8.0.9" + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-logical@9.0.0: + resolution: + { + integrity: sha512-A4LNd9dk3q/juEUA9Gd8ALhBO3TeOeYurnyHLlf2aAToD94VHR8c5Uv7KNmf8YVRhTxvWsyug4c5fKtARzyIRQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-merge-longhand@7.0.5: + resolution: + { + integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-rules@7.0.7: + resolution: + { + integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-font-values@7.0.1: + resolution: + { + integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-gradients@7.0.1: + resolution: + { + integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-params@7.0.5: + resolution: + { + integrity: sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.5: + resolution: + { + integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-nested@6.2.0: + resolution: + { + integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, + } + engines: { node: ">=12.0" } + peerDependencies: + postcss: ^8.2.14 + + postcss-nesting@14.0.0: + resolution: + { + integrity: sha512-YGFOfVrjxYfeGTS5XctP1WCI5hu8Lr9SmntjfRC+iX5hCihEO+QZl9Ra+pkjqkgoVdDKvb2JccpElcowhZtzpw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-normalize-charset@7.0.1: + resolution: + { + integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-display-values@7.0.1: + resolution: + { + integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-positions@7.0.1: + resolution: + { + integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-repeat-style@7.0.1: + resolution: + { + integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-string@7.0.1: + resolution: + { + integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-timing-functions@7.0.1: + resolution: + { + integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-unicode@7.0.5: + resolution: + { + integrity: sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-url@7.0.1: + resolution: + { + integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-whitespace@7.0.1: + resolution: + { + integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-opacity-percentage@3.0.0: + resolution: + { + integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==, + } + engines: { node: ">=18" } + peerDependencies: + postcss: ^8.4 + + postcss-ordered-values@7.0.2: + resolution: + { + integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-overflow-shorthand@7.0.0: + resolution: + { + integrity: sha512-9SLpjoUdGRoRrzoOdX66HbUs0+uDwfIAiXsRa7piKGOqPd6F4ZlON9oaDSP5r1Qpgmzw5L9Ht0undIK6igJPMA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-page-break@3.0.4: + resolution: + { + integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==, + } + peerDependencies: + postcss: ^8 + + postcss-place@11.0.0: + resolution: + { + integrity: sha512-fAifpyjQ+fuDRp2nmF95WbotqbpjdazebedahXdfBxy5sHembOLpBQ1cHveZD9ZmjK26tYM8tikeNaUlp/KfHA==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-preset-env@11.1.3: + resolution: + { + integrity: sha512-kZOfgzUc52yq2fJRZig7sHgWaHJoDOLABBoswe6TPTHgW3581VkP3eRj+Silhc7cJTomMjZZsyRHNjQ+bW11Gg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-pseudo-class-any-link@11.0.0: + resolution: + { + integrity: sha512-DNFZ4GMa3C3pU5dM+UCTG1CEeLtS1ZqV5DKSqCTJQMn1G5jnd/30fS8+A7H4o5bSD3MOcnx+VgI+xPE9Z5Wvig==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-reduce-initial@7.0.5: + resolution: + { + integrity: sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-reduce-transforms@7.0.1: + resolution: + { + integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-replace-overflow-wrap@4.0.0: + resolution: + { + integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==, + } + peerDependencies: + postcss: ^8.0.3 + + postcss-reporter@7.1.0: + resolution: + { + integrity: sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==, + } + engines: { node: ">=10" } + peerDependencies: + postcss: ^8.1.0 + + postcss-safe-parser@7.0.1: + resolution: + { + integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==, + } + engines: { node: ">=18.0" } + peerDependencies: + postcss: ^8.4.31 + + postcss-selector-not@9.0.0: + resolution: + { + integrity: sha512-xhAtTdHnVU2M/CrpYOPyRUvg3njhVlKmn2GNYXDaRJV9Ygx4d5OkSkc7NINzjUqnbDFtaKXlISOBeyMXU/zyFQ==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + postcss: ^8.4 + + postcss-selector-parser@6.0.10: + resolution: + { + integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==, + } + engines: { node: ">=4" } + + postcss-selector-parser@6.1.2: + resolution: + { + integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, + } + engines: { node: ">=4" } + + postcss-selector-parser@7.1.1: + resolution: + { + integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==, + } + engines: { node: ">=4" } + + postcss-svgo@7.1.0: + resolution: + { + integrity: sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >= 18 } + peerDependencies: + postcss: ^8.4.32 + + postcss-unique-selectors@7.0.4: + resolution: + { + integrity: sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + postcss-value-parser@4.2.0: + resolution: + { + integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, + } + + postcss@8.5.6: + resolution: + { + integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, + } + engines: { node: ^10 || ^12 || >=14 } + + prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: ">= 0.8.0" } + + prettier-linter-helpers@1.0.1: + resolution: + { + integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==, + } + engines: { node: ">=6.0.0" } + + prettier-plugin-organize-imports@4.3.0: + resolution: + { + integrity: sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==, + } + peerDependencies: + prettier: ">=2.0" + typescript: ">=2.9" + vue-tsc: ^2.1.0 || 3 + peerDependenciesMeta: + vue-tsc: + optional: true + + prettier@2.8.8: + resolution: + { + integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==, + } + engines: { node: ">=10.13.0" } + hasBin: true + + prettier@3.8.1: + resolution: + { + integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==, + } + engines: { node: ">=14" } + hasBin: true + + pretty-bytes@5.6.0: + resolution: + { + integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==, + } + engines: { node: ">=6" } + + pretty-bytes@6.1.1: + resolution: + { + integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==, + } + engines: { node: ^14.13.1 || >=16.0.0 } + + pretty-ms@9.3.0: + resolution: + { + integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==, + } + engines: { node: ">=18" } + + process-nextick-args@2.0.1: + resolution: + { + integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, + } + + proto-list@1.2.4: + resolution: + { + integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==, + } + + protocols@2.0.2: + resolution: + { + integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==, + } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: ">=6" } + + qified@0.6.0: + resolution: + { + integrity: sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==, + } + engines: { node: ">=20" } + + queue-microtask@1.2.3: + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } + + quick-lru@5.1.1: + resolution: + { + integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==, + } + engines: { node: ">=10" } + + raf@3.4.1: + resolution: + { + integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==, + } + + randombytes@2.1.0: + resolution: + { + integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==, + } + + rc@1.2.8: + resolution: + { + integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, + } + hasBin: true + + read-cache@1.0.0: + resolution: + { + integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==, + } + + read-package-up@11.0.0: + resolution: + { + integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==, + } + engines: { node: ">=18" } + + read-package-up@12.0.0: + resolution: + { + integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==, + } + engines: { node: ">=20" } + + read-pkg@10.1.0: + resolution: + { + integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==, + } + engines: { node: ">=20" } + + read-pkg@9.0.1: + resolution: + { + integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==, + } + engines: { node: ">=18" } + + readable-stream@2.3.8: + resolution: + { + integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, + } + + readable-stream@3.6.2: + resolution: + { + integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, + } + engines: { node: ">= 6" } + + readdirp@3.6.0: + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: ">=8.10.0" } + + reflect.getprototypeof@1.0.10: + resolution: + { + integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, + } + engines: { node: ">= 0.4" } + + regenerate-unicode-properties@10.2.2: + resolution: + { + integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==, + } + engines: { node: ">=4" } + + regenerate@1.4.2: + resolution: + { + integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==, + } + + regexp.prototype.flags@1.5.4: + resolution: + { + integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, + } + engines: { node: ">= 0.4" } + + regexpu-core@6.4.0: + resolution: + { + integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==, + } + engines: { node: ">=4" } + + registry-auth-token@5.1.1: + resolution: + { + integrity: sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==, + } + engines: { node: ">=14" } + + regjsgen@0.8.0: + resolution: + { + integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==, + } + + regjsparser@0.13.0: + resolution: + { + integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==, + } + hasBin: true + + regression@2.0.1: + resolution: + { + integrity: sha512-A4XYsc37dsBaNOgEjkJKzfJlE394IMmUPlI/p3TTI9u3T+2a+eox5Pr/CPUqF0eszeWZJPAc6QkroAhuUpWDJQ==, + } + + require-directory@2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: ">=0.10.0" } + + require-from-string@2.0.2: + resolution: + { + integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, + } + engines: { node: ">=0.10.0" } + + require-main-filename@2.0.0: + resolution: + { + integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==, + } + + resolve-alpn@1.2.1: + resolution: + { + integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==, + } + + resolve-dir@1.0.1: + resolution: + { + integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==, + } + engines: { node: ">=0.10.0" } + + resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: ">=4" } + + resolve-from@5.0.0: + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: ">=8" } + + resolve@1.22.11: + resolution: + { + integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==, + } + engines: { node: ">= 0.4" } + hasBin: true + + responselike@4.0.2: + resolution: + { + integrity: sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==, + } + engines: { node: ">=20" } + + restore-cursor@3.1.0: + resolution: + { + integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, + } + engines: { node: ">=8" } + + restore-cursor@5.1.0: + resolution: + { + integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==, + } + engines: { node: ">=18" } + + reusify@1.1.0: + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: ">=1.0.0", node: ">=0.10.0" } + + rfdc@1.4.1: + resolution: + { + integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, + } + + rgbcolor@1.0.1: + resolution: + { + integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==, + } + engines: { node: ">= 0.8.15" } + + rollup@2.79.2: + resolution: + { + integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==, + } + engines: { node: ">=10.0.0" } + hasBin: true + + rollup@4.57.1: + resolution: + { + integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } + hasBin: true + + run-applescript@7.1.0: + resolution: + { + integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==, + } + engines: { node: ">=18" } + + run-async@2.4.1: + resolution: + { + integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==, + } + engines: { node: ">=0.12.0" } + + run-parallel@1.2.0: + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } + + rxjs@6.6.7: + resolution: + { + integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==, + } + engines: { npm: ">=2.0.0" } + + rxjs@7.8.2: + resolution: + { + integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==, + } + + safe-array-concat@1.1.3: + resolution: + { + integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, + } + engines: { node: ">=0.4" } + + safe-buffer@5.1.2: + resolution: + { + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, + } + + safe-buffer@5.2.1: + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, + } + + safe-push-apply@1.0.0: + resolution: + { + integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, + } + engines: { node: ">= 0.4" } + + safe-regex-test@1.1.0: + resolution: + { + integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, + } + engines: { node: ">= 0.4" } + + safer-buffer@2.1.2: + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } + + sax@1.4.4: + resolution: + { + integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==, + } + engines: { node: ">=11.0.0" } + + semantic-release@25.0.3: + resolution: + { + integrity: sha512-WRgl5GcypwramYX4HV+eQGzUbD7UUbljVmS+5G1uMwX/wLgYuJAxGeerXJDMO2xshng4+FXqCgyB5QfClV6WjA==, + } + engines: { node: ^22.14.0 || >= 24.10.0 } + hasBin: true + + semver-regex@4.0.5: + resolution: + { + integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==, + } + engines: { node: ">=12" } + + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } + hasBin: true + + semver@7.7.4: + resolution: + { + integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==, + } + engines: { node: ">=10" } + hasBin: true + + serialize-javascript@6.0.2: + resolution: + { + integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==, + } + + set-blocking@2.0.0: + resolution: + { + integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==, + } + + set-function-length@1.2.2: + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: ">= 0.4" } + + set-function-name@2.0.2: + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: ">= 0.4" } + + set-proto@1.0.0: + resolution: + { + integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, + } + engines: { node: ">= 0.4" } + + sharp@0.34.5: + resolution: + { + integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + + shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: ">=8" } + + shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: ">=8" } + + side-channel-list@1.0.0: + resolution: + { + integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, + } + engines: { node: ">= 0.4" } + + side-channel-map@1.0.1: + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: ">= 0.4" } + + side-channel-weakmap@1.0.2: + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: ">= 0.4" } + + side-channel@1.1.0: + resolution: + { + integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, + } + engines: { node: ">= 0.4" } + + signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } + + signal-exit@4.1.0: + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: ">=14" } + + signale@1.4.0: + resolution: + { + integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==, + } + engines: { node: ">=6" } + + sirv@3.0.2: + resolution: + { + integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==, + } + engines: { node: ">=18" } + + skin-tone@2.0.0: + resolution: + { + integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==, + } + engines: { node: ">=8" } + + slash@5.1.0: + resolution: + { + integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==, + } + engines: { node: ">=14.16" } + + slice-ansi@4.0.0: + resolution: + { + integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==, + } + engines: { node: ">=10" } + + slice-ansi@7.1.2: + resolution: + { + integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==, + } + engines: { node: ">=18" } + + smob@1.6.1: + resolution: + { + integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==, + } + engines: { node: ">=20.0.0" } + + source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: ">=0.10.0" } + + source-map-support@0.5.21: + resolution: + { + integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, + } + + source-map@0.6.1: + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: ">=0.10.0" } + + source-map@0.8.0-beta.0: + resolution: + { + integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==, + } + engines: { node: ">= 8" } + deprecated: The work that was done in this beta branch won't be included in future versions + + sourcemap-codec@1.4.8: + resolution: + { + integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==, + } + deprecated: Please use @jridgewell/sourcemap-codec instead + + spawn-error-forwarder@1.0.0: + resolution: + { + integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==, + } + + spdx-correct@3.2.0: + resolution: + { + integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==, + } + + spdx-exceptions@2.5.0: + resolution: + { + integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==, + } + + spdx-expression-parse@3.0.1: + resolution: + { + integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==, + } + + spdx-license-ids@3.0.22: + resolution: + { + integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==, + } + + split2@1.0.0: + resolution: + { + integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==, + } + + split2@4.2.0: + resolution: + { + integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, + } + engines: { node: ">= 10.x" } + + stackblur-canvas@2.7.0: + resolution: + { + integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==, + } + engines: { node: ">=0.1.14" } + + stencil-wormhole@3.4.1: + resolution: + { + integrity: sha512-ppYTcWTJnIl4ZAKwF39LTA9f/ypHfbVefsHdN2hpMQGrR57wt1TieZo9tlCM/r1Y4SFiZ5yz/cjho564C921Xw==, + } + + stop-iteration-iterator@1.1.0: + resolution: + { + integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==, + } + engines: { node: ">= 0.4" } + + stream-combiner2@1.1.1: + resolution: + { + integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==, + } + + string-argv@0.3.2: + resolution: + { + integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==, + } + engines: { node: ">=0.6.19" } + + string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: ">=8" } + + string-width@7.2.0: + resolution: + { + integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==, + } + engines: { node: ">=18" } + + string-width@8.2.0: + resolution: + { + integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==, + } + engines: { node: ">=20" } + + string.prototype.matchall@4.0.12: + resolution: + { + integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==, + } + engines: { node: ">= 0.4" } + + string.prototype.trim@1.2.10: + resolution: + { + integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, + } + engines: { node: ">= 0.4" } + + string.prototype.trimend@1.0.9: + resolution: + { + integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, + } + engines: { node: ">= 0.4" } + + string.prototype.trimstart@1.0.8: + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: ">= 0.4" } + + string_decoder@1.1.1: + resolution: + { + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, + } + + string_decoder@1.3.0: + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, + } + + stringify-object@3.3.0: + resolution: + { + integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==, + } + engines: { node: ">=4" } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: ">=8" } + + strip-ansi@7.1.2: + resolution: + { + integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==, + } + engines: { node: ">=12" } + + strip-bom@3.0.0: + resolution: + { + integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, + } + engines: { node: ">=4" } + + strip-bom@4.0.0: + resolution: + { + integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==, + } + engines: { node: ">=8" } + + strip-comments@2.0.1: + resolution: + { + integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==, + } + engines: { node: ">=10" } + + strip-final-newline@2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: ">=6" } + + strip-final-newline@3.0.0: + resolution: + { + integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==, + } + engines: { node: ">=12" } + + strip-final-newline@4.0.0: + resolution: + { + integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==, + } + engines: { node: ">=18" } + + strip-json-comments@2.0.1: + resolution: + { + integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, + } + engines: { node: ">=0.10.0" } + + strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: ">=8" } + + style-mod@4.1.3: + resolution: + { + integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==, + } + + stylehacks@7.0.7: + resolution: + { + integrity: sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g==, + } + engines: { node: ^18.12.0 || ^20.9.0 || >=22.0 } + peerDependencies: + postcss: ^8.4.32 + + stylelint-config-recommended@18.0.0: + resolution: + { + integrity: sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + stylelint: ^17.0.0 + + stylelint-config-standard@40.0.0: + resolution: + { + integrity: sha512-EznGJxOUhtWck2r6dJpbgAdPATIzvpLdK9+i5qPd4Lx70es66TkBPljSg4wN3Qnc6c4h2n+WbUrUynQ3fanjHw==, + } + engines: { node: ">=20.19.0" } + peerDependencies: + stylelint: ^17.0.0 + + stylelint@17.3.0: + resolution: + { + integrity: sha512-1POV91lcEMhj6SLVaOeA0KlS9yattS+qq+cyWqP/nYzWco7K5jznpGH1ExngvPlTM9QF1Kjd2bmuzJu9TH2OcA==, + } + engines: { node: ">=20.19.0" } + hasBin: true + + sucrase@3.35.1: + resolution: + { + integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==, + } + engines: { node: ">=16 || 14 >=14.17" } + hasBin: true + + super-regex@1.1.0: + resolution: + { + integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==, + } + engines: { node: ">=18" } + + supports-color@10.2.2: + resolution: + { + integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==, + } + engines: { node: ">=18" } + + supports-color@5.5.0: + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: ">=4" } + + supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: ">=8" } + + supports-hyperlinks@3.2.0: + resolution: + { + integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==, + } + engines: { node: ">=14.18" } + + supports-hyperlinks@4.4.0: + resolution: + { + integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==, + } + engines: { node: ">=20" } + + supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: ">= 0.4" } + + svg-tags@1.0.0: + resolution: + { + integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==, + } + + svgo@4.0.0: + resolution: + { + integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==, + } + engines: { node: ">=16" } + hasBin: true + + synckit@0.11.12: + resolution: + { + integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + + table@6.9.0: + resolution: + { + integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==, + } + engines: { node: ">=10.0.0" } + + tagged-tag@1.0.0: + resolution: + { + integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==, + } + engines: { node: ">=20" } + + tailwindcss@3.4.19: + resolution: + { + integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==, + } + engines: { node: ">=14.0.0" } + hasBin: true + + temp-dir@2.0.0: + resolution: + { + integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==, + } + engines: { node: ">=8" } + + temp-dir@3.0.0: + resolution: + { + integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==, + } + engines: { node: ">=14.16" } + + tempy@0.6.0: + resolution: + { + integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==, + } + engines: { node: ">=10" } + + tempy@3.2.0: + resolution: + { + integrity: sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==, + } + engines: { node: ">=14.16" } + + terser@5.46.0: + resolution: + { + integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==, + } + engines: { node: ">=10" } + hasBin: true + + thenby@1.3.4: + resolution: + { + integrity: sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==, + } + + thenify-all@1.6.0: + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: ">=0.8" } + + thenify@3.3.1: + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } + + through2@2.0.5: + resolution: + { + integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==, + } + + through@2.3.8: + resolution: + { + integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, + } + + time-span@5.1.0: + resolution: + { + integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==, + } + engines: { node: ">=12" } + + tiny-inflate@1.0.3: + resolution: + { + integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==, + } + + tinyexec@1.0.2: + resolution: + { + integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==, + } + engines: { node: ">=18" } + + tinyglobby@0.2.15: + resolution: + { + integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, + } + engines: { node: ">=12.0.0" } + + tinyqueue@2.0.3: + resolution: + { + integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==, + } + + tmp@0.0.33: + resolution: + { + integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==, + } + engines: { node: ">=0.6.0" } + + to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: ">=8.0" } + + totalist@3.0.1: + resolution: + { + integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==, + } + engines: { node: ">=6" } + + tr46@0.0.3: + resolution: + { + integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==, + } + + tr46@1.0.1: + resolution: + { + integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==, + } + + traverse@0.6.8: + resolution: + { + integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==, + } + engines: { node: ">= 0.4" } + + ts-api-utils@2.4.0: + resolution: + { + integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==, + } + engines: { node: ">=18.12" } + peerDependencies: + typescript: ">=4.8.4" + + ts-interface-checker@0.1.13: + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } + + tslib@1.14.1: + resolution: + { + integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, + } + + tslib@2.8.1: + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } + + tunnel@0.0.6: + resolution: + { + integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==, + } + engines: { node: ">=0.6.11 <=0.7.0 || >=0.7.3" } + + type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: ">= 0.8.0" } + + type-fest@0.16.0: + resolution: + { + integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==, + } + engines: { node: ">=10" } + + type-fest@0.21.3: + resolution: + { + integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, + } + engines: { node: ">=10" } + + type-fest@1.4.0: + resolution: + { + integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==, + } + engines: { node: ">=10" } + + type-fest@2.19.0: + resolution: + { + integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==, + } + engines: { node: ">=12.20" } + + type-fest@4.41.0: + resolution: + { + integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, + } + engines: { node: ">=16" } + + type-fest@5.4.4: + resolution: + { + integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==, + } + engines: { node: ">=20" } + + typed-array-buffer@1.0.3: + resolution: + { + integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, + } + engines: { node: ">= 0.4" } + + typed-array-byte-length@1.0.3: + resolution: + { + integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, + } + engines: { node: ">= 0.4" } + + typed-array-byte-offset@1.0.4: + resolution: + { + integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, + } + engines: { node: ">= 0.4" } + + typed-array-length@1.0.7: + resolution: + { + integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, + } + engines: { node: ">= 0.4" } + + typescript-eslint@8.56.0: + resolution: + { + integrity: sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.0.0" + + typescript@5.9.3: + resolution: + { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: ">=14.17" } + hasBin: true + + uglify-js@3.19.3: + resolution: + { + integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==, + } + engines: { node: ">=0.8.0" } + hasBin: true + + unbox-primitive@1.1.0: + resolution: + { + integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, + } + engines: { node: ">= 0.4" } + + undici-types@7.14.0: + resolution: + { + integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==, + } + + undici@6.23.0: + resolution: + { + integrity: sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==, + } + engines: { node: ">=18.17" } + + undici@7.22.0: + resolution: + { + integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==, + } + engines: { node: ">=20.18.1" } + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: + { + integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==, + } + engines: { node: ">=4" } + + unicode-emoji-modifier-base@1.0.0: + resolution: + { + integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==, + } + engines: { node: ">=4" } + + unicode-match-property-ecmascript@2.0.0: + resolution: + { + integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==, + } + engines: { node: ">=4" } + + unicode-match-property-value-ecmascript@2.2.1: + resolution: + { + integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==, + } + engines: { node: ">=4" } + + unicode-properties@1.4.1: + resolution: + { + integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==, + } + + unicode-property-aliases-ecmascript@2.2.0: + resolution: + { + integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==, + } + engines: { node: ">=4" } + + unicode-trie@2.0.0: + resolution: + { + integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==, + } + + unicorn-magic@0.1.0: + resolution: + { + integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==, + } + engines: { node: ">=18" } + + unicorn-magic@0.3.0: + resolution: + { + integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==, + } + engines: { node: ">=18" } + + unicorn-magic@0.4.0: + resolution: + { + integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==, + } + engines: { node: ">=20" } + + unique-string@2.0.0: + resolution: + { + integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==, + } + engines: { node: ">=8" } + + unique-string@3.0.0: + resolution: + { + integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==, + } + engines: { node: ">=12" } + + universal-user-agent@7.0.3: + resolution: + { + integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==, + } + + universalify@2.0.1: + resolution: + { + integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, + } + engines: { node: ">= 10.0.0" } + + unplugin-utils@0.3.1: + resolution: + { + integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==, + } + engines: { node: ">=20.19.0" } + + upath@1.2.0: + resolution: + { + integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==, + } + engines: { node: ">=4" } + + update-browserslist-db@1.2.3: + resolution: + { + integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==, + } + hasBin: true + peerDependencies: + browserslist: ">= 4.21.0" + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + url-join@4.0.1: + resolution: + { + integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==, + } + + url-join@5.0.0: + resolution: + { + integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + + validate-npm-package-license@3.0.4: + resolution: + { + integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==, + } + + vite-dev-rpc@1.1.0: + resolution: + { + integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==, + } + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 + + vite-hot-client@2.1.0: + resolution: + { + integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==, + } + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + + vite-plugin-codeigniter@2.0.0: + resolution: + { + integrity: sha512-F4S23BlXu1Yhb2k/cHeB3DV8q1BN+GNFf63jDFRqL4vwdv12/RWK+hBhNSsUUQguklogluza6GL+U1W8t/ba0w==, + } + peerDependencies: + vite: ^7.0.0 + + vite-plugin-inspect@11.3.3: + resolution: + { + integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==, + } + engines: { node: ">=14" } + peerDependencies: + "@nuxt/kit": "*" + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + "@nuxt/kit": + optional: true + + vite-plugin-pwa@1.2.0: + resolution: + { + integrity: sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==, + } + engines: { node: ">=16.0.0" } + peerDependencies: + "@vite-pwa/assets-generator": ^1.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + workbox-build: ^7.4.0 + workbox-window: ^7.4.0 + peerDependenciesMeta: + "@vite-pwa/assets-generator": + optional: true + + vite-plugin-static-copy@3.2.0: + resolution: + { + integrity: sha512-g2k9z8B/1Bx7D4wnFjPLx9dyYGrqWMLTpwTtPHhcU+ElNZP2O4+4OsyaficiDClus0dzVhdGvoGFYMJxoXZ12Q==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + vite@7.3.1: + resolution: + { + integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + hasBin: true + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + w3c-keyname@2.2.8: + resolution: + { + integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==, + } + + wavesurfer.js@7.12.1: + resolution: + { + integrity: sha512-NswPjVHxk0Q1F/VMRemCPUzSojjuHHisQrBqQiRXg7MVbe3f5vQ6r0rTTXA/a/neC/4hnOEC4YpXca4LpH0SUg==, + } + + wcwidth@1.0.1: + resolution: + { + integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, + } + + web-worker@1.2.0: + resolution: + { + integrity: sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==, + } + + webidl-conversions@3.0.1: + resolution: + { + integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==, + } + + webidl-conversions@4.0.2: + resolution: + { + integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==, + } + + whatwg-url@5.0.0: + resolution: + { + integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==, + } + + whatwg-url@7.1.0: + resolution: + { + integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==, + } + + which-boxed-primitive@1.1.1: + resolution: + { + integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, + } + engines: { node: ">= 0.4" } + + which-builtin-type@1.2.1: + resolution: + { + integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, + } + engines: { node: ">= 0.4" } + + which-collection@1.0.2: + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: ">= 0.4" } + + which-module@2.0.1: + resolution: + { + integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==, + } + + which-typed-array@1.1.20: + resolution: + { + integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==, + } + engines: { node: ">= 0.4" } + + which@1.3.1: + resolution: + { + integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==, + } + hasBin: true + + which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: ">= 8" } + hasBin: true + + word-wrap@1.2.5: + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: ">=0.10.0" } + + wordwrap@1.0.0: + resolution: + { + integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==, + } + + workbox-background-sync@7.4.0: + resolution: + { + integrity: sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==, + } + + workbox-broadcast-update@7.4.0: + resolution: + { + integrity: sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==, + } + + workbox-build@7.4.0: + resolution: + { + integrity: sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==, + } + engines: { node: ">=20.0.0" } + + workbox-cacheable-response@7.4.0: + resolution: + { + integrity: sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==, + } + + workbox-core@7.4.0: + resolution: + { + integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==, + } + + workbox-expiration@7.4.0: + resolution: + { + integrity: sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==, + } + + workbox-google-analytics@7.4.0: + resolution: + { + integrity: sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==, + } + + workbox-navigation-preload@7.4.0: + resolution: + { + integrity: sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==, + } + + workbox-precaching@7.4.0: + resolution: + { + integrity: sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==, + } + + workbox-range-requests@7.4.0: + resolution: + { + integrity: sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==, + } + + workbox-recipes@7.4.0: + resolution: + { + integrity: sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==, + } + + workbox-routing@7.4.0: + resolution: + { + integrity: sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==, + } + + workbox-strategies@7.4.0: + resolution: + { + integrity: sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==, + } + + workbox-streams@7.4.0: + resolution: + { + integrity: sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==, + } + + workbox-sw@7.4.0: + resolution: + { + integrity: sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==, + } + + workbox-window@7.4.0: + resolution: + { + integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==, + } + + wrap-ansi@6.2.0: + resolution: + { + integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==, + } + engines: { node: ">=8" } + + wrap-ansi@7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: ">=10" } + + wrap-ansi@9.0.2: + resolution: + { + integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==, + } + engines: { node: ">=18" } + + wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + write-file-atomic@7.0.0: + resolution: + { + integrity: sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==, + } + engines: { node: ^20.17.0 || >=22.9.0 } + + wsl-utils@0.1.0: + resolution: + { + integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==, + } + engines: { node: ">=18" } + + xml-formatter@3.6.7: + resolution: + { + integrity: sha512-IsfFYJQuoDqtUlKhm4EzeoBOb+fQwzQVeyxxAQ0sThn/nFnQmyLPTplqq4yRhaOENH/tAyujD2TBfIYzUKB6hg==, + } + engines: { node: ">= 16" } + + xml-parser-xo@4.1.5: + resolution: + { + integrity: sha512-TxyRxk9sTOUg3glxSIY6f0nfuqRll2OEF8TspLgh5mZkLuBgheCn3zClcDSGJ58TvNmiwyCCuat4UajPud/5Og==, + } + engines: { node: ">= 16" } + + xmldoc@2.0.3: + resolution: + { + integrity: sha512-6gRk4NY/Jvg67xn7OzJuxLRsGgiXBaPUQplVJ/9l99uIugxh4FTOewYz5ic8WScj7Xx/2WvhENiQKwkK9RpE4w==, + } + engines: { node: ">=12.0.0" } + + xtend@4.0.2: + resolution: + { + integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, + } + engines: { node: ">=0.4" } + + y18n@4.0.3: + resolution: + { + integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==, + } + + y18n@5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: ">=10" } + + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + + yaml@2.8.2: + resolution: + { + integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==, + } + engines: { node: ">= 14.6" } + hasBin: true + + yargs-parser@18.1.3: + resolution: + { + integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==, + } + engines: { node: ">=6" } + + yargs-parser@20.2.9: + resolution: + { + integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, + } + engines: { node: ">=10" } + + yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: ">=12" } + + yargs-parser@22.0.0: + resolution: + { + integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=23 } + + yargs@15.4.1: + resolution: + { + integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==, + } + engines: { node: ">=8" } + + yargs@16.2.0: + resolution: + { + integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==, + } + engines: { node: ">=10" } + + yargs@17.7.2: + resolution: + { + integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, + } + engines: { node: ">=12" } + + yargs@18.0.0: + resolution: + { + integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==, + } + engines: { node: ^20.19.0 || ^22.12.0 || >=23 } + + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: ">=10" } + + yoctocolors@2.1.2: + resolution: + { + integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==, + } + engines: { node: ">=18" } + + zod@4.3.6: + resolution: + { + integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==, + } + +snapshots: + "@actions/core@3.0.0": + dependencies: + "@actions/exec": 3.0.0 + "@actions/http-client": 4.0.0 + + "@actions/exec@3.0.0": + dependencies: + "@actions/io": 3.0.2 + + "@actions/http-client@4.0.0": + dependencies: + tunnel: 0.0.6 + undici: 6.23.0 + + "@actions/io@3.0.2": {} + + "@alloc/quick-lru@5.2.0": {} + + "@amcharts/amcharts4-geodata@4.1.31": {} + + "@amcharts/amcharts4@4.10.40": + dependencies: + "@babel/runtime": 7.28.6 + core-js: 3.48.0 + d3-force: 3.0.0 + d3-geo: 3.1.1 + d3-geo-projection: 4.0.0 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + pdfmake: 0.2.23 + polylabel: 1.1.0 + raf: 3.4.1 + regression: 2.0.1 + rgbcolor: 1.0.1 + stackblur-canvas: 2.7.0 + tslib: 2.8.1 + + "@apideck/better-ajv-errors@0.3.6(ajv@8.18.0)": + dependencies: + ajv: 8.18.0 + json-schema: 0.4.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + + "@babel/code-frame@7.29.0": + dependencies: + "@babel/helper-validator-identifier": 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + "@babel/compat-data@7.29.0": {} + + "@babel/core@7.29.0": + dependencies: + "@babel/code-frame": 7.29.0 + "@babel/generator": 7.29.1 + "@babel/helper-compilation-targets": 7.28.6 + "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) + "@babel/helpers": 7.28.6 + "@babel/parser": 7.29.0 + "@babel/template": 7.28.6 + "@babel/traverse": 7.29.0 + "@babel/types": 7.29.0 + "@jridgewell/remapping": 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/generator@7.29.1": + dependencies: + "@babel/parser": 7.29.0 + "@babel/types": 7.29.0 + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + jsesc: 3.1.0 + + "@babel/helper-annotate-as-pure@7.27.3": + dependencies: + "@babel/types": 7.29.0 + + "@babel/helper-compilation-targets@7.28.6": + dependencies: + "@babel/compat-data": 7.29.0 + "@babel/helper-validator-option": 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + "@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-annotate-as-pure": 7.27.3 + "@babel/helper-member-expression-to-functions": 7.28.5 + "@babel/helper-optimise-call-expression": 7.27.1 + "@babel/helper-replace-supers": 7.28.6(@babel/core@7.29.0) + "@babel/helper-skip-transparent-expression-wrappers": 7.27.1 + "@babel/traverse": 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-annotate-as-pure": 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + "@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@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 + transitivePeerDependencies: + - supports-color + + "@babel/helper-globals@7.28.0": {} + + "@babel/helper-member-expression-to-functions@7.28.5": + dependencies: + "@babel/traverse": 7.29.0 + "@babel/types": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-module-imports@7.28.6": + dependencies: + "@babel/traverse": 7.29.0 + "@babel/types": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-imports": 7.28.6 + "@babel/helper-validator-identifier": 7.28.5 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-optimise-call-expression@7.27.1": + dependencies: + "@babel/types": 7.29.0 + + "@babel/helper-plugin-utils@7.28.6": {} + + "@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-annotate-as-pure": 7.27.3 + "@babel/helper-wrap-function": 7.28.6 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-member-expression-to-functions": 7.28.5 + "@babel/helper-optimise-call-expression": 7.27.1 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-skip-transparent-expression-wrappers@7.27.1": + dependencies: + "@babel/traverse": 7.29.0 + "@babel/types": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helper-string-parser@7.27.1": {} + + "@babel/helper-validator-identifier@7.28.5": {} + + "@babel/helper-validator-option@7.27.1": {} + + "@babel/helper-wrap-function@7.28.6": + dependencies: + "@babel/template": 7.28.6 + "@babel/traverse": 7.29.0 + "@babel/types": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/helpers@7.28.6": + dependencies: + "@babel/template": 7.28.6 + "@babel/types": 7.29.0 + + "@babel/parser@7.29.0": + dependencies: + "@babel/types": 7.29.0 + + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-skip-transparent-expression-wrappers": 7.27.1 + "@babel/plugin-transform-optional-chaining": 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + + "@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-remap-async-to-generator": 7.27.1(@babel/core@7.29.0) + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-imports": 7.28.6 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-remap-async-to-generator": 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-class-features-plugin": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-class-features-plugin": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-annotate-as-pure": 7.27.3 + "@babel/helper-compilation-targets": 7.28.6 + "@babel/helper-globals": 7.28.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-replace-supers": 7.28.6(@babel/core@7.29.0) + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/template": 7.28.6 + + "@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/plugin-transform-destructuring": 7.28.5(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-skip-transparent-expression-wrappers": 7.27.1 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-compilation-targets": 7.28.6 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-validator-identifier": 7.28.5 + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-transforms": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-compilation-targets": 7.28.6 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/plugin-transform-destructuring": 7.28.5(@babel/core@7.29.0) + "@babel/plugin-transform-parameters": 7.27.7(@babel/core@7.29.0) + "@babel/traverse": 7.29.0 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-replace-supers": 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-skip-transparent-expression-wrappers": 7.27.1 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-class-features-plugin": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-annotate-as-pure": 7.27.3 + "@babel/helper-create-class-features-plugin": 7.28.6(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-skip-transparent-expression-wrappers": 7.27.1 + transitivePeerDependencies: + - supports-color + + "@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-create-regexp-features-plugin": 7.28.5(@babel/core@7.29.0) + "@babel/helper-plugin-utils": 7.28.6 + + "@babel/preset-env@7.29.0(@babel/core@7.29.0)": + dependencies: + "@babel/compat-data": 7.29.0 + "@babel/core": 7.29.0 + "@babel/helper-compilation-targets": 7.28.6 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/helper-validator-option": 7.27.1 + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": 7.28.5(@babel/core@7.29.0) + "@babel/plugin-bugfix-safari-class-field-initializer-scope": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + "@babel/plugin-syntax-import-assertions": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-syntax-import-attributes": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-syntax-unicode-sets-regex": 7.18.6(@babel/core@7.29.0) + "@babel/plugin-transform-arrow-functions": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-async-generator-functions": 7.29.0(@babel/core@7.29.0) + "@babel/plugin-transform-async-to-generator": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-block-scoped-functions": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-block-scoping": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-class-properties": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-class-static-block": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-classes": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-computed-properties": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-destructuring": 7.28.5(@babel/core@7.29.0) + "@babel/plugin-transform-dotall-regex": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-duplicate-keys": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": 7.29.0(@babel/core@7.29.0) + "@babel/plugin-transform-dynamic-import": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-explicit-resource-management": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-exponentiation-operator": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-export-namespace-from": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-for-of": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-function-name": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-json-strings": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-literals": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-logical-assignment-operators": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-member-expression-literals": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-modules-amd": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-modules-commonjs": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-modules-systemjs": 7.29.0(@babel/core@7.29.0) + "@babel/plugin-transform-modules-umd": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-named-capturing-groups-regex": 7.29.0(@babel/core@7.29.0) + "@babel/plugin-transform-new-target": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-nullish-coalescing-operator": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-numeric-separator": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-object-rest-spread": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-object-super": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-optional-catch-binding": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-optional-chaining": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-parameters": 7.27.7(@babel/core@7.29.0) + "@babel/plugin-transform-private-methods": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-private-property-in-object": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-property-literals": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-regenerator": 7.29.0(@babel/core@7.29.0) + "@babel/plugin-transform-regexp-modifiers": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-reserved-words": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-shorthand-properties": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-spread": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-sticky-regex": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-template-literals": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-typeof-symbol": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-unicode-escapes": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-unicode-property-regex": 7.28.6(@babel/core@7.29.0) + "@babel/plugin-transform-unicode-regex": 7.27.1(@babel/core@7.29.0) + "@babel/plugin-transform-unicode-sets-regex": 7.28.6(@babel/core@7.29.0) + "@babel/preset-modules": 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-plugin-utils": 7.28.6 + "@babel/types": 7.29.0 + esutils: 2.0.3 + + "@babel/runtime@7.28.6": {} + + "@babel/template@7.28.6": + dependencies: + "@babel/code-frame": 7.29.0 + "@babel/parser": 7.29.0 + "@babel/types": 7.29.0 + + "@babel/traverse@7.29.0": + dependencies: + "@babel/code-frame": 7.29.0 + "@babel/generator": 7.29.1 + "@babel/helper-globals": 7.28.0 + "@babel/parser": 7.29.0 + "@babel/template": 7.28.6 + "@babel/types": 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + "@babel/types@7.29.0": + dependencies: + "@babel/helper-string-parser": 7.27.1 + "@babel/helper-validator-identifier": 7.28.5 + + "@cacheable/memory@2.0.7": + dependencies: + "@cacheable/utils": 2.3.4 + "@keyv/bigmap": 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + "@cacheable/utils@2.3.4": + dependencies: + hashery: 1.5.0 + keyv: 5.6.0 + + "@codemirror/autocomplete@6.20.0": + dependencies: + "@codemirror/language": 6.12.1 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + + "@codemirror/commands@6.10.2": + dependencies: + "@codemirror/language": 6.12.1 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + + "@codemirror/lang-css@6.3.1": + dependencies: + "@codemirror/autocomplete": 6.20.0 + "@codemirror/language": 6.12.1 + "@codemirror/state": 6.5.4 + "@lezer/common": 1.5.1 + "@lezer/css": 1.3.1 + + "@codemirror/lang-html@6.4.11": + dependencies: + "@codemirror/autocomplete": 6.20.0 + "@codemirror/lang-css": 6.3.1 + "@codemirror/lang-javascript": 6.2.4 + "@codemirror/language": 6.12.1 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + "@lezer/css": 1.3.1 + "@lezer/html": 1.3.13 + + "@codemirror/lang-javascript@6.2.4": + dependencies: + "@codemirror/autocomplete": 6.20.0 + "@codemirror/language": 6.12.1 + "@codemirror/lint": 6.9.4 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + "@lezer/javascript": 1.5.4 + + "@codemirror/lang-xml@6.1.0": + dependencies: + "@codemirror/autocomplete": 6.20.0 + "@codemirror/language": 6.12.1 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + "@lezer/xml": 1.0.6 + + "@codemirror/language@6.12.1": + dependencies: + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + "@lezer/common": 1.5.1 + "@lezer/highlight": 1.2.3 + "@lezer/lr": 1.4.8 + style-mod: 4.1.3 + + "@codemirror/lint@6.9.4": + dependencies: + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + crelt: 1.0.6 + + "@codemirror/search@6.6.0": + dependencies: + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + crelt: 1.0.6 + + "@codemirror/state@6.5.4": + dependencies: + "@marijn/find-cluster-break": 1.0.2 + + "@codemirror/view@6.39.14": + dependencies: + "@codemirror/state": 6.5.4 + crelt: 1.0.6 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + "@colors/colors@1.5.0": + optional: true + + "@commitlint/cli@20.4.2(@types/node@24.7.0)(typescript@5.9.3)": + dependencies: + "@commitlint/format": 20.4.0 + "@commitlint/lint": 20.4.2 + "@commitlint/load": 20.4.0(@types/node@24.7.0)(typescript@5.9.3) + "@commitlint/read": 20.4.0 + "@commitlint/types": 20.4.0 + tinyexec: 1.0.2 + yargs: 17.7.2 + transitivePeerDependencies: + - "@types/node" + - typescript + + "@commitlint/config-conventional@20.4.2": + dependencies: + "@commitlint/types": 20.4.0 + conventional-changelog-conventionalcommits: 9.1.0 + + "@commitlint/config-validator@20.4.0": + dependencies: + "@commitlint/types": 20.4.0 + ajv: 8.18.0 + + "@commitlint/ensure@20.4.1": + dependencies: + "@commitlint/types": 20.4.0 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + "@commitlint/execute-rule@20.0.0": {} + + "@commitlint/format@20.4.0": + dependencies: + "@commitlint/types": 20.4.0 + picocolors: 1.1.1 + + "@commitlint/is-ignored@20.4.1": + dependencies: + "@commitlint/types": 20.4.0 + semver: 7.7.4 + + "@commitlint/lint@20.4.2": + dependencies: + "@commitlint/is-ignored": 20.4.1 + "@commitlint/parse": 20.4.1 + "@commitlint/rules": 20.4.2 + "@commitlint/types": 20.4.0 + + "@commitlint/load@20.4.0(@types/node@24.7.0)(typescript@5.9.3)": + dependencies: + "@commitlint/config-validator": 20.4.0 + "@commitlint/execute-rule": 20.0.0 + "@commitlint/resolve-extends": 20.4.0 + "@commitlint/types": 20.4.0 + cosmiconfig: 9.0.0(typescript@5.9.3) + cosmiconfig-typescript-loader: 6.2.0(@types/node@24.7.0)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3) + is-plain-obj: 4.1.0 + lodash.mergewith: 4.6.2 + picocolors: 1.1.1 + transitivePeerDependencies: + - "@types/node" + - typescript + + "@commitlint/message@20.4.0": {} + + "@commitlint/parse@20.4.1": + dependencies: + "@commitlint/types": 20.4.0 + conventional-changelog-angular: 8.1.0 + conventional-commits-parser: 6.2.1 + + "@commitlint/read@20.4.0": + dependencies: + "@commitlint/top-level": 20.4.0 + "@commitlint/types": 20.4.0 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + tinyexec: 1.0.2 + + "@commitlint/resolve-extends@20.4.0": + dependencies: + "@commitlint/config-validator": 20.4.0 + "@commitlint/types": 20.4.0 + global-directory: 4.0.1 + import-meta-resolve: 4.2.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + "@commitlint/rules@20.4.2": + dependencies: + "@commitlint/ensure": 20.4.1 + "@commitlint/message": 20.4.0 + "@commitlint/to-lines": 20.0.0 + "@commitlint/types": 20.4.0 + + "@commitlint/to-lines@20.0.0": {} + + "@commitlint/top-level@20.4.0": + dependencies: + escalade: 3.2.0 + + "@commitlint/types@20.4.0": + dependencies: + conventional-commits-parser: 6.2.1 + picocolors: 1.1.1 + + "@csstools/cascade-layer-name-parser@3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + + "@csstools/color-helpers@6.0.1": {} + + "@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + + "@csstools/css-color-parser@4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)": + dependencies: + "@csstools/color-helpers": 6.0.1 + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + + "@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)": + dependencies: + "@csstools/css-tokenizer": 4.0.0 + + "@csstools/css-syntax-patches-for-csstree@1.0.27": {} + + "@csstools/css-tokenizer@4.0.0": {} + + "@csstools/media-query-list-parser@5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + + "@csstools/postcss-alpha-function@2.0.2(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-cascade-layers@6.0.0(postcss@8.5.6)": + dependencies: + "@csstools/selector-specificity": 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + "@csstools/postcss-color-function-display-p3-linear@2.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-color-function@5.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-color-mix-function@4.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-color-mix-variadic-function-arguments@2.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-content-alt-text@3.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-contrast-color-function@3.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-exponential-functions@3.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-font-format-keywords@5.0.0(postcss@8.5.6)": + dependencies: + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-gamut-mapping@3.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-gradients-interpolation-method@6.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-hwb-function@5.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-ic-unit@5.0.0(postcss@8.5.6)": + dependencies: + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-initial@3.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/postcss-is-pseudo-class@6.0.0(postcss@8.5.6)": + dependencies: + "@csstools/selector-specificity": 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + "@csstools/postcss-light-dark-function@3.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-logical-float-and-clear@4.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/postcss-logical-overflow@3.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/postcss-logical-overscroll-behavior@3.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/postcss-logical-resize@4.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-logical-viewport-units@4.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-tokenizer": 4.0.0 + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-media-minmax@3.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/media-query-list-parser": 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.6 + + "@csstools/postcss-media-queries-aspect-ratio-number-values@4.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/media-query-list-parser": 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.6 + + "@csstools/postcss-mixins@1.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-nested-calc@5.0.0(postcss@8.5.6)": + dependencies: + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-normalize-display-values@5.0.1(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-oklab-function@5.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-position-area-property@2.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/postcss-progressive-custom-properties@5.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-property-rule-prelude-list@2.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-random-function@3.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-relative-color-syntax@4.0.1(postcss@8.5.6)": + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + "@csstools/postcss-scope-pseudo-class@5.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + "@csstools/postcss-sign-functions@2.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-stepped-value-functions@5.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-syntax-descriptor-syntax-production@2.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-system-ui-font-family@2.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-text-decoration-shorthand@5.0.2(postcss@8.5.6)": + dependencies: + "@csstools/color-helpers": 6.0.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + "@csstools/postcss-trigonometric-functions@5.0.0(postcss@8.5.6)": + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + + "@csstools/postcss-unset-value@5.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@csstools/selector-resolve-nested@4.0.0(postcss-selector-parser@7.1.1)": + dependencies: + postcss-selector-parser: 7.1.1 + + "@csstools/selector-specificity@6.0.0(postcss-selector-parser@7.1.1)": + dependencies: + postcss-selector-parser: 7.1.1 + + "@csstools/utilities@3.0.0(postcss@8.5.6)": + dependencies: + postcss: 8.5.6 + + "@emnapi/runtime@1.8.1": + dependencies: + tslib: 2.8.1 + optional: true + + "@epic-web/invariant@1.0.0": {} + + "@esbuild/aix-ppc64@0.27.3": + optional: true + + "@esbuild/android-arm64@0.27.3": + optional: true + + "@esbuild/android-arm@0.27.3": + optional: true + + "@esbuild/android-x64@0.27.3": + optional: true + + "@esbuild/darwin-arm64@0.27.3": + optional: true + + "@esbuild/darwin-x64@0.27.3": + optional: true + + "@esbuild/freebsd-arm64@0.27.3": + optional: true + + "@esbuild/freebsd-x64@0.27.3": + optional: true + + "@esbuild/linux-arm64@0.27.3": + optional: true + + "@esbuild/linux-arm@0.27.3": + optional: true + + "@esbuild/linux-ia32@0.27.3": + optional: true + + "@esbuild/linux-loong64@0.27.3": + optional: true + + "@esbuild/linux-mips64el@0.27.3": + optional: true + + "@esbuild/linux-ppc64@0.27.3": + optional: true + + "@esbuild/linux-riscv64@0.27.3": + optional: true + + "@esbuild/linux-s390x@0.27.3": + optional: true + + "@esbuild/linux-x64@0.27.3": + optional: true + + "@esbuild/netbsd-arm64@0.27.3": + optional: true + + "@esbuild/netbsd-x64@0.27.3": + optional: true + + "@esbuild/openbsd-arm64@0.27.3": + optional: true + + "@esbuild/openbsd-x64@0.27.3": + optional: true + + "@esbuild/openharmony-arm64@0.27.3": + optional: true + + "@esbuild/sunos-x64@0.27.3": + optional: true + + "@esbuild/win32-arm64@0.27.3": + optional: true + + "@esbuild/win32-ia32@0.27.3": + optional: true + + "@esbuild/win32-x64@0.27.3": + optional: true + + "@eslint-community/eslint-utils@4.9.1(eslint@10.0.0(jiti@1.21.7))": + dependencies: + eslint: 10.0.0(jiti@1.21.7) + eslint-visitor-keys: 3.4.3 + + "@eslint-community/regexpp@4.12.2": {} + + "@eslint/config-array@0.23.1": + dependencies: + "@eslint/object-schema": 3.0.1 + debug: 4.4.3 + minimatch: 10.2.1 + transitivePeerDependencies: + - supports-color + + "@eslint/config-helpers@0.5.2": + dependencies: + "@eslint/core": 1.1.0 + + "@eslint/core@1.1.0": + dependencies: + "@types/json-schema": 7.0.15 + + "@eslint/eslintrc@3.3.3": + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + "@eslint/js@10.0.1(eslint@10.0.0(jiti@1.21.7))": + optionalDependencies: + eslint: 10.0.0(jiti@1.21.7) + + "@eslint/object-schema@3.0.1": {} + + "@eslint/plugin-kit@0.6.0": + dependencies: + "@eslint/core": 1.1.0 + levn: 0.4.1 + + "@floating-ui/core@1.7.4": + dependencies: + "@floating-ui/utils": 0.2.10 + + "@floating-ui/dom@1.7.5": + dependencies: + "@floating-ui/core": 1.7.4 + "@floating-ui/utils": 0.2.10 + + "@floating-ui/utils@0.2.10": {} + + "@foliojs-fork/fontkit@1.9.2": + dependencies: + "@foliojs-fork/restructure": 2.0.2 + brotli: 1.3.3 + clone: 1.0.4 + deep-equal: 1.1.2 + dfa: 1.2.0 + tiny-inflate: 1.0.3 + unicode-properties: 1.4.1 + unicode-trie: 2.0.0 + + "@foliojs-fork/linebreak@1.1.2": + dependencies: + base64-js: 1.3.1 + unicode-trie: 2.0.0 + + "@foliojs-fork/pdfkit@0.15.3": + dependencies: + "@foliojs-fork/fontkit": 1.9.2 + "@foliojs-fork/linebreak": 1.1.2 + crypto-js: 4.2.0 + jpeg-exif: 1.1.4 + png-js: 1.0.0 + + "@foliojs-fork/restructure@2.0.2": {} + + "@github/clipboard-copy-element@1.3.0": {} + + "@github/hotkey@3.1.1": {} + + "@github/markdown-toolbar-element@2.2.3": {} + + "@github/relative-time-element@5.0.0": {} + + "@humanfs/core@0.19.1": {} + + "@humanfs/node@0.16.7": + dependencies: + "@humanfs/core": 0.19.1 + "@humanwhocodes/retry": 0.4.3 + + "@humanwhocodes/module-importer@1.0.1": {} + + "@humanwhocodes/retry@0.4.3": {} + + "@img/colour@1.0.0": {} + + "@img/sharp-darwin-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-darwin-arm64": 1.2.4 + optional: true + + "@img/sharp-darwin-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-darwin-x64": 1.2.4 + optional: true + + "@img/sharp-libvips-darwin-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-darwin-x64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-arm@1.2.4": + optional: true + + "@img/sharp-libvips-linux-ppc64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-riscv64@1.2.4": + optional: true + + "@img/sharp-libvips-linux-s390x@1.2.4": + optional: true + + "@img/sharp-libvips-linux-x64@1.2.4": + optional: true + + "@img/sharp-libvips-linuxmusl-arm64@1.2.4": + optional: true + + "@img/sharp-libvips-linuxmusl-x64@1.2.4": + optional: true + + "@img/sharp-linux-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm64": 1.2.4 + optional: true + + "@img/sharp-linux-arm@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-arm": 1.2.4 + optional: true + + "@img/sharp-linux-ppc64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-ppc64": 1.2.4 + optional: true + + "@img/sharp-linux-riscv64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-riscv64": 1.2.4 + optional: true + + "@img/sharp-linux-s390x@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-s390x": 1.2.4 + optional: true + + "@img/sharp-linux-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linux-x64": 1.2.4 + optional: true + + "@img/sharp-linuxmusl-arm64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + optional: true + + "@img/sharp-linuxmusl-x64@0.34.5": + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + optional: true + + "@img/sharp-wasm32@0.34.5": + dependencies: + "@emnapi/runtime": 1.8.1 + optional: true + + "@img/sharp-win32-arm64@0.34.5": + optional: true + + "@img/sharp-win32-ia32@0.34.5": + optional: true + + "@img/sharp-win32-x64@0.34.5": + optional: true + + "@isaacs/cliui@9.0.0": {} + + "@jridgewell/gen-mapping@0.3.13": + dependencies: + "@jridgewell/sourcemap-codec": 1.5.5 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/remapping@2.3.5": + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/resolve-uri@3.1.2": {} + + "@jridgewell/source-map@0.3.11": + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + "@jridgewell/trace-mapping": 0.3.31 + + "@jridgewell/sourcemap-codec@1.5.5": {} + + "@jridgewell/trace-mapping@0.3.31": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.5.5 + + "@keyv/bigmap@1.3.1(keyv@5.6.0)": + dependencies: + hashery: 1.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + + "@keyv/serialize@1.1.1": {} + + "@lezer/common@1.5.1": {} + + "@lezer/css@1.3.1": + dependencies: + "@lezer/common": 1.5.1 + "@lezer/highlight": 1.2.3 + "@lezer/lr": 1.4.8 + + "@lezer/highlight@1.2.3": + dependencies: + "@lezer/common": 1.5.1 + + "@lezer/html@1.3.13": + dependencies: + "@lezer/common": 1.5.1 + "@lezer/highlight": 1.2.3 + "@lezer/lr": 1.4.8 + + "@lezer/javascript@1.5.4": + dependencies: + "@lezer/common": 1.5.1 + "@lezer/highlight": 1.2.3 + "@lezer/lr": 1.4.8 + + "@lezer/lr@1.4.8": + dependencies: + "@lezer/common": 1.5.1 + + "@lezer/xml@1.0.6": + dependencies: + "@lezer/common": 1.5.1 + "@lezer/highlight": 1.2.3 + "@lezer/lr": 1.4.8 + + "@lit-labs/ssr-dom-shim@1.5.1": {} + + "@lit/context@1.1.6": + dependencies: + "@lit/reactive-element": 2.1.2 + + "@lit/reactive-element@2.1.2": + dependencies: + "@lit-labs/ssr-dom-shim": 1.5.1 + + "@marijn/find-cluster-break@1.0.2": {} + + "@nodelib/fs.scandir@2.1.5": + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: 1.2.0 + + "@nodelib/fs.stat@2.0.5": {} + + "@nodelib/fs.walk@1.2.8": + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: 1.20.1 + + "@octokit/auth-token@6.0.0": {} + + "@octokit/core@7.0.6": + dependencies: + "@octokit/auth-token": 6.0.0 + "@octokit/graphql": 9.0.3 + "@octokit/request": 10.0.7 + "@octokit/request-error": 7.1.0 + "@octokit/types": 16.0.0 + before-after-hook: 4.0.0 + universal-user-agent: 7.0.3 + + "@octokit/endpoint@11.0.3": + dependencies: + "@octokit/types": 16.0.0 + universal-user-agent: 7.0.3 + + "@octokit/graphql@9.0.3": + dependencies: + "@octokit/request": 10.0.7 + "@octokit/types": 16.0.0 + universal-user-agent: 7.0.3 + + "@octokit/openapi-types@27.0.0": {} + + "@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)": + dependencies: + "@octokit/core": 7.0.6 + "@octokit/types": 16.0.0 + + "@octokit/plugin-retry@8.1.0(@octokit/core@7.0.6)": + dependencies: + "@octokit/core": 7.0.6 + "@octokit/request-error": 7.1.0 + "@octokit/types": 16.0.0 + bottleneck: 2.19.5 + + "@octokit/plugin-throttling@11.0.3(@octokit/core@7.0.6)": + dependencies: + "@octokit/core": 7.0.6 + "@octokit/types": 16.0.0 + bottleneck: 2.19.5 + + "@octokit/request-error@7.1.0": + dependencies: + "@octokit/types": 16.0.0 + + "@octokit/request@10.0.7": + dependencies: + "@octokit/endpoint": 11.0.3 + "@octokit/request-error": 7.1.0 + "@octokit/types": 16.0.0 + fast-content-type-parse: 3.0.0 + universal-user-agent: 7.0.3 + + "@octokit/types@16.0.0": + dependencies: + "@octokit/openapi-types": 27.0.0 + + "@patternfly/elements@4.3.1": + dependencies: + "@lit/context": 1.1.6 + "@patternfly/icons": 1.0.3 + "@patternfly/pfe-core": 5.0.6 + lit: 3.3.2 + tslib: 2.8.1 + + "@patternfly/icons@1.0.3": {} + + "@patternfly/pfe-core@5.0.6": + dependencies: + "@lit/context": 1.1.6 + lit: 3.3.2 + + "@pkgr/core@0.2.9": {} + + "@pnpm/config.env-replace@1.1.0": {} + + "@pnpm/network.ca-file@1.0.2": + dependencies: + graceful-fs: 4.2.10 + + "@pnpm/npm-conf@3.0.2": + dependencies: + "@pnpm/config.env-replace": 1.1.0 + "@pnpm/network.ca-file": 1.0.2 + config-chain: 1.1.13 + + "@polka/url@1.0.0-next.29": {} + + "@rollup/plugin-babel@5.3.1(@babel/core@7.29.0)(rollup@2.79.2)": + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-module-imports": 7.28.6 + "@rollup/pluginutils": 3.1.0(rollup@2.79.2) + rollup: 2.79.2 + transitivePeerDependencies: + - supports-color + + "@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2)": + dependencies: + "@rollup/pluginutils": 5.3.0(rollup@2.79.2) + "@types/resolve": 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 2.79.2 + + "@rollup/plugin-replace@2.4.2(rollup@2.79.2)": + dependencies: + "@rollup/pluginutils": 3.1.0(rollup@2.79.2) + magic-string: 0.25.9 + rollup: 2.79.2 + + "@rollup/plugin-terser@0.4.4(rollup@2.79.2)": + dependencies: + serialize-javascript: 6.0.2 + smob: 1.6.1 + terser: 5.46.0 + optionalDependencies: + rollup: 2.79.2 + + "@rollup/pluginutils@3.1.0(rollup@2.79.2)": + dependencies: + "@types/estree": 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.79.2 + + "@rollup/pluginutils@5.3.0(rollup@2.79.2)": + dependencies: + "@types/estree": 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 2.79.2 + + "@rollup/rollup-android-arm-eabi@4.57.1": + optional: true + + "@rollup/rollup-android-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-x64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-arm64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-x64@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-musleabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-s390x-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-musl@4.57.1": + optional: true + + "@rollup/rollup-openbsd-x64@4.57.1": + optional: true + + "@rollup/rollup-openharmony-arm64@4.57.1": + optional: true + + "@rollup/rollup-win32-arm64-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-ia32-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-msvc@4.57.1": + optional: true + + "@sec-ant/readable-stream@0.4.1": {} + + "@semantic-release/changelog@6.0.3(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@semantic-release/error": 3.0.0 + aggregate-error: 3.1.0 + fs-extra: 11.3.3 + lodash: 4.17.23 + semantic-release: 25.0.3(typescript@5.9.3) + + "@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + conventional-changelog-angular: 8.1.0 + conventional-changelog-writer: 8.2.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.2.1 + debug: 4.4.3 + import-from-esm: 2.0.0 + lodash-es: 4.17.23 + micromatch: 4.0.8 + semantic-release: 25.0.3(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + "@semantic-release/error@3.0.0": {} + + "@semantic-release/error@4.0.0": {} + + "@semantic-release/exec@7.1.0(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@semantic-release/error": 4.0.0 + aggregate-error: 3.1.0 + debug: 4.4.3 + execa: 9.6.1 + lodash-es: 4.17.23 + parse-json: 8.3.0 + semantic-release: 25.0.3(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + "@semantic-release/git@10.0.1(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@semantic-release/error": 3.0.0 + aggregate-error: 3.1.0 + debug: 4.4.3 + dir-glob: 3.0.1 + execa: 5.1.1 + lodash: 4.17.23 + micromatch: 4.0.8 + p-reduce: 2.1.0 + semantic-release: 25.0.3(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + "@semantic-release/github@12.0.6(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@octokit/core": 7.0.6 + "@octokit/plugin-paginate-rest": 14.0.0(@octokit/core@7.0.6) + "@octokit/plugin-retry": 8.1.0(@octokit/core@7.0.6) + "@octokit/plugin-throttling": 11.0.3(@octokit/core@7.0.6) + "@semantic-release/error": 4.0.0 + aggregate-error: 5.0.0 + debug: 4.4.3 + dir-glob: 3.0.1 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + issue-parser: 7.0.1 + lodash-es: 4.17.23 + mime: 4.1.0 + p-filter: 4.1.0 + semantic-release: 25.0.3(typescript@5.9.3) + tinyglobby: 0.2.15 + undici: 7.22.0 + url-join: 5.0.0 + transitivePeerDependencies: + - supports-color + + "@semantic-release/gitlab@13.3.0(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@semantic-release/error": 4.0.0 + aggregate-error: 5.0.0 + debug: 4.4.3 + dir-glob: 3.0.1 + escape-string-regexp: 5.0.0 + formdata-node: 6.0.3 + fs-extra: 11.3.3 + globby: 14.1.0 + got: 14.6.6 + hpagent: 1.2.0 + lodash-es: 4.17.23 + parse-url: 10.0.3 + semantic-release: 25.0.3(typescript@5.9.3) + url-join: 4.0.1 + transitivePeerDependencies: + - supports-color + + "@semantic-release/npm@13.1.4(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + "@actions/core": 3.0.0 + "@semantic-release/error": 4.0.0 + aggregate-error: 5.0.0 + env-ci: 11.2.0 + execa: 9.6.1 + fs-extra: 11.3.3 + lodash-es: 4.17.23 + nerf-dart: 1.0.0 + normalize-url: 8.1.1 + npm: 11.10.0 + rc: 1.2.8 + read-pkg: 10.1.0 + registry-auth-token: 5.1.1 + semantic-release: 25.0.3(typescript@5.9.3) + semver: 7.7.4 + tempy: 3.2.0 + + "@semantic-release/release-notes-generator@14.1.0(semantic-release@25.0.3(typescript@5.9.3))": + dependencies: + conventional-changelog-angular: 8.1.0 + conventional-changelog-writer: 8.2.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.2.1 + debug: 4.4.3 + get-stream: 7.0.1 + import-from-esm: 2.0.0 + into-stream: 7.0.0 + lodash-es: 4.17.23 + read-package-up: 11.0.0 + semantic-release: 25.0.3(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + "@sindresorhus/is@4.6.0": {} + + "@sindresorhus/is@7.2.0": {} + + "@sindresorhus/merge-streams@2.3.0": {} + + "@sindresorhus/merge-streams@4.0.0": {} + + "@stencil/core@2.5.2": {} + + "@surma/rollup-plugin-off-main-thread@2.2.3": + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.25.9 + string.prototype.matchall: 4.0.12 + + "@tailwindcss/forms@0.5.11(tailwindcss@3.4.19(yaml@2.8.2))": + dependencies: + mini-svg-data-uri: 1.4.4 + tailwindcss: 3.4.19(yaml@2.8.2) + + "@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(yaml@2.8.2))": + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19(yaml@2.8.2) + + "@types/eslint@9.6.1": + dependencies: + "@types/estree": 1.0.8 + "@types/json-schema": 7.0.15 + optional: true + + "@types/esrecurse@4.3.1": {} + + "@types/estree@0.0.39": {} + + "@types/estree@1.0.8": {} + + "@types/fscreen@1.0.4": {} + + "@types/geojson@7946.0.16": {} + + "@types/http-cache-semantics@4.2.0": {} + + "@types/json-schema@7.0.15": {} + + "@types/leaflet@1.9.21": + dependencies: + "@types/geojson": 7946.0.16 + + "@types/node@24.7.0": + dependencies: + undici-types: 7.14.0 + + "@types/normalize-package-data@2.4.4": {} + + "@types/resolve@1.20.2": {} + + "@types/trusted-types@2.0.7": {} + + "@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3)": + dependencies: + "@eslint-community/regexpp": 4.12.2 + "@typescript-eslint/parser": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + "@typescript-eslint/scope-manager": 8.56.0 + "@typescript-eslint/type-utils": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + "@typescript-eslint/utils": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.56.0 + eslint: 10.0.0(jiti@1.21.7) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/parser@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3)": + dependencies: + "@typescript-eslint/scope-manager": 8.56.0 + "@typescript-eslint/types": 8.56.0 + "@typescript-eslint/typescript-estree": 8.56.0(typescript@5.9.3) + "@typescript-eslint/visitor-keys": 8.56.0 + debug: 4.4.3 + eslint: 10.0.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/project-service@8.56.0(typescript@5.9.3)": + dependencies: + "@typescript-eslint/tsconfig-utils": 8.56.0(typescript@5.9.3) + "@typescript-eslint/types": 8.56.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/scope-manager@8.56.0": + dependencies: + "@typescript-eslint/types": 8.56.0 + "@typescript-eslint/visitor-keys": 8.56.0 + + "@typescript-eslint/tsconfig-utils@8.56.0(typescript@5.9.3)": + dependencies: + typescript: 5.9.3 + + "@typescript-eslint/type-utils@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3)": + dependencies: + "@typescript-eslint/types": 8.56.0 + "@typescript-eslint/typescript-estree": 8.56.0(typescript@5.9.3) + "@typescript-eslint/utils": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.0.0(jiti@1.21.7) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/types@8.56.0": {} + + "@typescript-eslint/typescript-estree@8.56.0(typescript@5.9.3)": + dependencies: + "@typescript-eslint/project-service": 8.56.0(typescript@5.9.3) + "@typescript-eslint/tsconfig-utils": 8.56.0(typescript@5.9.3) + "@typescript-eslint/types": 8.56.0 + "@typescript-eslint/visitor-keys": 8.56.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/utils@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3)": + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@10.0.0(jiti@1.21.7)) + "@typescript-eslint/scope-manager": 8.56.0 + "@typescript-eslint/types": 8.56.0 + "@typescript-eslint/typescript-estree": 8.56.0(typescript@5.9.3) + eslint: 10.0.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + "@typescript-eslint/visitor-keys@8.56.0": + dependencies: + "@typescript-eslint/types": 8.56.0 + eslint-visitor-keys: 5.0.0 + + "@vime/core@5.4.1": + dependencies: + "@stencil/core": 2.5.2 + "@types/fscreen": 1.0.4 + fscreen: 1.2.0 + mitt: 3.0.1 + stencil-wormhole: 3.4.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@7.1.4: {} + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + aggregate-error@5.0.0: + dependencies: + clean-stack: 5.3.0 + indent-string: 5.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + all-contributors-cli@6.26.1: + dependencies: + "@babel/runtime": 7.28.6 + async: 3.2.6 + chalk: 4.1.2 + didyoumean: 1.2.2 + inquirer: 7.3.3 + json-fixer: 1.6.15 + lodash: 4.17.23 + node-fetch: 2.7.0 + pify: 5.0.0 + yargs: 15.4.1 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - encoding + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + argparse@2.0.1: {} + + argv-formatter@1.0.0: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-ify@1.0.0: {} + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + astral-regex@2.0.0: {} + + async-function@1.0.0: {} + + async@3.2.6: {} + + at-least-node@1.0.0: {} + + autoprefixer@10.4.24(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001770 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.29.0): + dependencies: + "@babel/compat-data": 7.29.0 + "@babel/core": 7.29.0 + "@babel/helper-define-polyfill-provider": 0.6.6(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.29.0): + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-define-polyfill-provider": 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.29.0): + dependencies: + "@babel/core": 7.29.0 + "@babel/helper-define-polyfill-provider": 0.6.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + balanced-match@1.0.2: {} + + balanced-match@3.0.1: {} + + balanced-match@4.0.3: {} + + base64-js@1.3.1: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.0: {} + + before-after-hook@4.0.0: {} + + binary-extensions@2.3.0: {} + + birpc@2.9.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + boolbase@1.0.0: {} + + bottleneck@2.19.5: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.2: + dependencies: + balanced-match: 4.0.3 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001770 + electron-to-chromium: 1.5.286 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + byte-counter@0.1.0: {} + + cacheable-lookup@7.0.0: {} + + cacheable-request@13.0.18: + dependencies: + "@types/http-cache-semantics": 4.2.0 + get-stream: 9.0.1 + http-cache-semantics: 4.2.0 + keyv: 5.6.0 + mimic-response: 4.0.0 + normalize-url: 8.1.1 + responselike: 4.0.2 + + cacheable@2.3.2: + dependencies: + "@cacheable/memory": 2.0.7 + "@cacheable/utils": 2.3.4 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.6.0 + + cachedir@2.3.0: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + 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 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + camelcase@5.3.1: {} + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001770 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001770: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + char-regex@1.0.2: {} + + chardet@0.7.0: {} + + choices.js@11.1.0: + dependencies: + fuse.js: 7.1.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@4.4.0: {} + + clean-stack@2.2.0: {} + + clean-stack@5.3.0: + dependencies: + escape-string-regexp: 5.0.0 + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + + cli-spinners@2.9.2: {} + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + "@colors/colors": 1.5.0 + + cli-truncate@5.1.1: + dependencies: + slice-ansi: 7.1.2 + string-width: 8.2.0 + + cli-width@3.0.0: {} + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + + clone@1.0.4: {} + + codemirror@6.0.2: + dependencies: + "@codemirror/autocomplete": 6.20.0 + "@codemirror/commands": 6.10.2 + "@codemirror/language": 6.12.1 + "@codemirror/lint": 6.9.4 + "@codemirror/search": 6.6.0 + "@codemirror/state": 6.5.4 + "@codemirror/view": 6.39.14 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colord@2.9.3: {} + + colorette@2.0.20: {} + + commander@11.1.0: {} + + commander@14.0.3: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@7.2.0: {} + + commitizen@4.3.1(@types/node@24.7.0)(typescript@5.9.3): + dependencies: + cachedir: 2.3.0 + cz-conventional-changelog: 3.3.0(@types/node@24.7.0)(typescript@5.9.3) + dedent: 0.7.0 + detect-indent: 6.1.0 + find-node-modules: 2.1.3 + find-root: 1.1.0 + fs-extra: 9.1.0 + glob: 7.2.3 + inquirer: 8.2.5 + is-utf8: 0.2.1 + lodash: 4.17.21 + minimist: 1.2.7 + strip-bom: 4.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - "@types/node" + - typescript + + common-tags@1.8.2: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + concat-map@0.0.1: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + conventional-changelog-angular@8.1.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@9.1.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-writer@8.2.0: + dependencies: + conventional-commits-filter: 5.0.0 + handlebars: 4.7.8 + meow: 13.2.0 + semver: 7.7.4 + + conventional-commit-types@3.0.0: {} + + conventional-commits-filter@5.0.0: {} + + conventional-commits-parser@6.2.1: + dependencies: + meow: 13.2.0 + + convert-hrtime@5.0.0: {} + + convert-source-map@2.0.0: {} + + core-js-compat@3.48.0: + dependencies: + browserslist: 4.28.1 + + core-js@3.48.0: {} + + core-util-is@1.0.3: {} + + cosmiconfig-typescript-loader@6.2.0(@types/node@24.7.0)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3): + dependencies: + "@types/node": 24.7.0 + cosmiconfig: 9.0.0(typescript@5.9.3) + jiti: 2.6.1 + typescript: 5.9.3 + + cosmiconfig@9.0.0(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + + crelt@1.0.6: {} + + cross-env@10.1.0: + dependencies: + "@epic-web/invariant": 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-js@4.2.0: {} + + crypto-random-string@2.0.0: {} + + crypto-random-string@4.0.0: + dependencies: + type-fest: 1.4.0 + + css-blank-pseudo@8.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + css-declaration-sorter@7.3.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + css-functions-list@3.3.3: {} + + css-has-pseudo@8.0.0(postcss@8.5.6): + dependencies: + "@csstools/selector-specificity": 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + css-prefers-color-scheme@11.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssdb@8.7.1: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@7.0.10(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + css-declaration-sorter: 7.3.1(postcss@8.5.6) + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-calc: 10.1.1(postcss@8.5.6) + postcss-colormin: 7.0.5(postcss@8.5.6) + postcss-convert-values: 7.0.8(postcss@8.5.6) + postcss-discard-comments: 7.0.5(postcss@8.5.6) + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-discard-overridden: 7.0.1(postcss@8.5.6) + postcss-merge-longhand: 7.0.5(postcss@8.5.6) + postcss-merge-rules: 7.0.7(postcss@8.5.6) + postcss-minify-font-values: 7.0.1(postcss@8.5.6) + postcss-minify-gradients: 7.0.1(postcss@8.5.6) + postcss-minify-params: 7.0.5(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-normalize-charset: 7.0.1(postcss@8.5.6) + postcss-normalize-display-values: 7.0.1(postcss@8.5.6) + postcss-normalize-positions: 7.0.1(postcss@8.5.6) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.6) + postcss-normalize-string: 7.0.1(postcss@8.5.6) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.6) + postcss-normalize-unicode: 7.0.5(postcss@8.5.6) + postcss-normalize-url: 7.0.1(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-ordered-values: 7.0.2(postcss@8.5.6) + postcss-reduce-initial: 7.0.5(postcss@8.5.6) + postcss-reduce-transforms: 7.0.1(postcss@8.5.6) + postcss-svgo: 7.1.0(postcss@8.5.6) + postcss-unique-selectors: 7.0.4(postcss@8.5.6) + + cssnano-utils@5.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + cssnano@7.1.2(postcss@8.5.6): + dependencies: + cssnano-preset-default: 7.0.10(postcss@8.5.6) + lilconfig: 3.1.3 + postcss: 8.5.6 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + cz-conventional-changelog@3.3.0(@types/node@24.7.0)(typescript@5.9.3): + dependencies: + chalk: 2.4.2 + commitizen: 4.3.1(@types/node@24.7.0)(typescript@5.9.3) + conventional-commit-types: 3.0.0 + lodash.map: 4.6.0 + longest: 2.0.1 + word-wrap: 1.2.5 + optionalDependencies: + "@commitlint/load": 20.4.0(@types/node@24.7.0)(typescript@5.9.3) + transitivePeerDependencies: + - "@types/node" + - typescript + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-ease@3.0.1: {} + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-geo-projection@4.0.0: + dependencies: + commander: 7.2.0 + d3-array: 3.2.4 + d3-geo: 3.1.1 + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-quadtree@3.0.1: {} + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + dargs@8.1.0: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + decompress-response@10.0.0: + dependencies: + mimic-response: 4.0.0 + + dedent@0.7.0: {} + + deep-equal@1.1.2: + dependencies: + is-arguments: 1.2.0 + is-date-object: 1.1.0 + is-regex: 1.2.1 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.4 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-lazy-prop@3.0.0: {} + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + detect-file@1.0.0: {} + + detect-indent@6.1.0: {} + + detect-libc@2.1.2: {} + + dfa@1.2.0: {} + + didyoumean@1.2.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dlv@1.1.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-to-chromium@1.5.286: {} + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + emojilib@2.4.0: {} + + entities@4.5.0: {} + + env-ci@11.2.0: + dependencies: + execa: 8.0.1 + java-properties: 1.0.2 + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser-es@1.0.5: {} + + es-abstract@1.24.1: + 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.20 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.27.3: + optionalDependencies: + "@esbuild/aix-ppc64": 0.27.3 + "@esbuild/android-arm": 0.27.3 + "@esbuild/android-arm64": 0.27.3 + "@esbuild/android-x64": 0.27.3 + "@esbuild/darwin-arm64": 0.27.3 + "@esbuild/darwin-x64": 0.27.3 + "@esbuild/freebsd-arm64": 0.27.3 + "@esbuild/freebsd-x64": 0.27.3 + "@esbuild/linux-arm": 0.27.3 + "@esbuild/linux-arm64": 0.27.3 + "@esbuild/linux-ia32": 0.27.3 + "@esbuild/linux-loong64": 0.27.3 + "@esbuild/linux-mips64el": 0.27.3 + "@esbuild/linux-ppc64": 0.27.3 + "@esbuild/linux-riscv64": 0.27.3 + "@esbuild/linux-s390x": 0.27.3 + "@esbuild/linux-x64": 0.27.3 + "@esbuild/netbsd-arm64": 0.27.3 + "@esbuild/netbsd-x64": 0.27.3 + "@esbuild/openbsd-arm64": 0.27.3 + "@esbuild/openbsd-x64": 0.27.3 + "@esbuild/openharmony-arm64": 0.27.3 + "@esbuild/sunos-x64": 0.27.3 + "@esbuild/win32-arm64": 0.27.3 + "@esbuild/win32-ia32": 0.27.3 + "@esbuild/win32-x64": 0.27.3 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-config-prettier@10.1.8(eslint@10.0.0(jiti@1.21.7)): + dependencies: + eslint: 10.0.0(jiti@1.21.7) + + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.0(jiti@1.21.7)))(eslint@10.0.0(jiti@1.21.7))(prettier@3.8.1): + dependencies: + eslint: 10.0.0(jiti@1.21.7) + prettier: 3.8.1 + prettier-linter-helpers: 1.0.1 + synckit: 0.11.12 + optionalDependencies: + "@types/eslint": 9.6.1 + eslint-config-prettier: 10.1.8(eslint@10.0.0(jiti@1.21.7)) + + eslint-scope@9.1.0: + dependencies: + "@types/esrecurse": 4.3.1 + "@types/estree": 1.0.8 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.0: {} + + eslint@10.0.0(jiti@1.21.7): + dependencies: + "@eslint-community/eslint-utils": 4.9.1(eslint@10.0.0(jiti@1.21.7)) + "@eslint-community/regexpp": 4.12.2 + "@eslint/config-array": 0.23.1 + "@eslint/config-helpers": 0.5.2 + "@eslint/core": 1.1.0 + "@eslint/plugin-kit": 0.6.0 + "@humanfs/node": 0.16.7 + "@humanwhocodes/module-importer": 1.0.1 + "@humanwhocodes/retry": 0.4.3 + "@types/estree": 1.0.8 + ajv: 6.12.6 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.0 + eslint-visitor-keys: 5.0.0 + espree: 11.1.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.1 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + espree@11.1.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 5.0.0 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@1.0.1: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.4: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + execa@9.6.1: + dependencies: + "@sindresorhus/merge-streams": 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + fast-content-type-parse@3.0.0: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + "@nodelib/fs.stat": 2.0.5 + "@nodelib/fs.walk": 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.0: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + figures@2.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + + file-entry-cache@11.1.2: + dependencies: + flat-cache: 6.1.20 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-node-modules@2.1.3: + dependencies: + findup-sync: 4.0.0 + merge: 2.1.1 + + find-root@1.1.0: {} + + find-up-simple@1.0.1: {} + + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-versions@6.0.0: + dependencies: + semver-regex: 4.0.5 + super-regex: 1.1.0 + + findup-sync@4.0.0: + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 4.0.8 + resolve-dir: 1.0.1 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat-cache@6.1.20: + dependencies: + cacheable: 2.3.2 + flatted: 3.3.3 + hookified: 1.15.1 + + flatpickr@4.6.13: {} + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data-encoder@4.1.0: {} + + formdata-node@6.0.3: {} + + fraction.js@5.3.4: {} + + from2@2.3.0: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fscreen@1.2.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function-timeout@1.0.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + fuse.js@7.1.0: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.5.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-own-enumerable-property-symbols@3.0.2: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + get-stream@7.0.1: {} + + get-stream@8.0.1: {} + + get-stream@9.0.1: + dependencies: + "@sec-ant/readable-stream": 0.4.1 + is-stream: 4.0.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + git-log-parser@1.2.1: + dependencies: + argv-formatter: 1.0.0 + spawn-error-forwarder: 1.0.0 + split2: 1.0.0 + stream-combiner2: 1.1.1 + through2: 2.0.5 + traverse: 0.6.8 + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.2.3 + minimatch: 10.2.1 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.1 + + glob@13.0.5: + dependencies: + minimatch: 10.2.1 + minipass: 7.1.3 + path-scurry: 2.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globals@14.0.0: {} + + globals@17.3.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globby@14.1.0: + dependencies: + "@sindresorhus/merge-streams": 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + + globby@16.1.1: + dependencies: + "@sindresorhus/merge-streams": 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + is-path-inside: 4.0.0 + slash: 5.1.0 + unicorn-magic: 0.4.0 + + globjoin@0.1.4: {} + + gopd@1.2.0: {} + + got@14.6.6: + dependencies: + "@sindresorhus/is": 7.2.0 + byte-counter: 0.1.0 + cacheable-lookup: 7.0.0 + cacheable-request: 13.0.18 + decompress-response: 10.0.0 + form-data-encoder: 4.1.0 + http2-wrapper: 2.2.1 + keyv: 5.6.0 + lowercase-keys: 3.0.0 + p-cancelable: 4.0.1 + responselike: 4.0.2 + type-fest: 4.41.0 + + graceful-fs@4.2.10: {} + + graceful-fs@4.2.11: {} + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-flag@5.0.1: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hashery@1.5.0: + dependencies: + hookified: 1.15.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + highlight.js@10.7.3: {} + + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + + hook-std@4.0.0: {} + + hookified@1.15.1: {} + + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + hosted-git-info@9.0.2: + dependencies: + lru-cache: 11.2.6 + + hpagent@1.2.0: {} + + html-tags@5.1.0: {} + + htmlfy@1.0.1: {} + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@2.2.1: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + human-signals@5.0.0: {} + + human-signals@8.0.1: {} + + husky@9.1.7: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + idb@7.1.1: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-from-esm@2.0.0: + dependencies: + debug: 4.4.3 + import-meta-resolve: 4.2.0 + transitivePeerDependencies: + - supports-color + + import-meta-resolve@4.2.0: {} + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + indent-string@5.0.0: {} + + index-to-position@1.2.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@4.1.1: {} + + inquirer@7.3.3: + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.23 + mute-stream: 0.0.8 + run-async: 2.4.1 + rxjs: 6.6.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + + inquirer@8.2.5: + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + internmap@2.0.3: {} + + into-stream@7.0.0: + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-ci@4.1.0: + dependencies: + ci-info: 4.4.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-docker@3.0.0: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.5.0 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-interactive@1.0.0: {} + + is-map@2.0.3: {} + + is-module@1.0.0: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-obj@1.0.1: {} + + is-obj@2.0.0: {} + + is-path-inside@4.0.0: {} + + is-plain-obj@4.1.0: {} + + is-plain-object@5.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-regexp@1.0.0: {} + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-stream@4.0.1: {} + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-unicode-supported@0.1.0: {} + + is-unicode-supported@2.1.0: {} + + is-utf8@0.2.1: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-windows@1.0.2: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + issue-parser@7.0.1: + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + + jackspeak@4.2.3: + dependencies: + "@isaacs/cliui": 9.0.0 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 + + java-properties@1.0.2: {} + + jiti@1.21.7: {} + + jiti@2.6.1: {} + + jpeg-exif@1.1.4: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-fixer@1.6.15: + dependencies: + "@babel/runtime": 7.28.6 + chalk: 4.1.2 + pegjs: 0.10.0 + + json-parse-better-errors@1.0.2: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonpointer@5.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + keyv@5.6.0: + dependencies: + "@keyv/serialize": 1.1.1 + + kind-of@6.0.3: {} + + known-css-properties@0.37.0: {} + + leaflet.markercluster@1.5.3(leaflet@1.9.4): + dependencies: + leaflet: 1.9.4 + + leaflet@1.9.4: {} + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + lint-staged@16.2.7: + dependencies: + commander: 14.0.3 + listr2: 9.0.5 + micromatch: 4.0.8 + nano-spawn: 2.0.0 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.2 + + listr2@9.0.5: + dependencies: + cli-truncate: 5.1.1 + colorette: 2.0.20 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + lit-element@4.2.2: + dependencies: + "@lit-labs/ssr-dom-shim": 1.5.1 + "@lit/reactive-element": 2.1.2 + lit-html: 3.3.2 + + lit-html@3.3.2: + dependencies: + "@types/trusted-types": 2.0.7 + + lit@3.3.2: + dependencies: + "@lit/reactive-element": 2.1.2 + lit-element: 4.2.2 + lit-html: 3.3.2 + + load-json-file@4.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.17.23: {} + + lodash.camelcase@4.3.0: {} + + lodash.capitalize@4.2.1: {} + + lodash.debounce@4.0.8: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + + lodash.kebabcase@4.1.1: {} + + lodash.map@4.6.0: {} + + lodash.memoize@4.1.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.sortby@4.7.0: {} + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash.uniq@4.5.0: {} + + lodash.uniqby@4.7.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + lodash@4.17.23: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + + longest@2.0.1: {} + + lowercase-keys@3.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@11.2.6: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + make-asynchronous@1.0.1: + dependencies: + p-event: 6.0.1 + type-fest: 4.41.0 + web-worker: 1.2.0 + + marked-terminal@7.3.0(marked@15.0.12): + dependencies: + ansi-escapes: 7.3.0 + ansi-regex: 6.2.2 + chalk: 5.6.2 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 15.0.12 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + + marked@15.0.12: {} + + marked@17.0.3: {} + + math-intrinsics@1.1.0: {} + + mathml-tag-names@4.0.0: {} + + mdn-data@2.0.28: {} + + mdn-data@2.12.2: {} + + meow@12.1.1: {} + + meow@13.2.0: {} + + meow@14.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + merge@2.1.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime@4.1.0: {} + + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + mimic-response@4.0.0: {} + + mini-svg-data-uri@1.4.4: {} + + minimatch@10.2.1: + dependencies: + brace-expansion: 5.0.2 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.7: {} + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + mitt@3.0.1: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + mute-stream@0.0.8: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nano-spawn@2.0.0: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + nerf-dart@1.0.0: {} + + node-emoji@2.2.0: + dependencies: + "@sindresorhus/is": 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-releases@2.0.27: {} + + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + + normalize-package-data@8.0.0: + dependencies: + hosted-git-info: 9.0.2 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + normalize-url@8.1.1: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + npm@11.10.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.4: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + ohash@2.0.11: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + os-tmpdir@1.0.2: {} + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-cancelable@4.0.1: {} + + p-each-series@3.0.0: {} + + p-event@6.0.1: + dependencies: + p-timeout: 6.1.4 + + p-filter@4.1.0: + dependencies: + p-map: 7.0.4 + + p-is-promise@3.0.0: {} + + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@7.0.4: {} + + p-reduce@2.1.0: {} + + p-reduce@3.0.0: {} + + p-timeout@6.1.4: {} + + p-try@1.0.0: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + pako@0.2.9: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@4.0.0: + dependencies: + error-ex: 1.3.4 + json-parse-better-errors: 1.0.2 + + parse-json@5.2.0: + dependencies: + "@babel/code-frame": 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-json@8.3.0: + dependencies: + "@babel/code-frame": 7.29.0 + index-to-position: 1.2.0 + type-fest: 4.41.0 + + parse-ms@4.0.0: {} + + parse-passwd@1.0.0: {} + + parse-path@7.1.0: + dependencies: + protocols: 2.0.2 + + parse-url@10.0.3: + dependencies: + parse-path: 7.1.0 + + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@2.0.1: + dependencies: + lru-cache: 11.2.6 + minipass: 7.1.3 + + path-type@4.0.0: {} + + path-type@6.0.0: {} + + pathe@2.0.3: {} + + pdfmake@0.2.23: + dependencies: + "@foliojs-fork/linebreak": 1.1.2 + "@foliojs-fork/pdfkit": 0.15.3 + iconv-lite: 0.7.2 + xmldoc: 2.0.3 + + pegjs@0.10.0: {} + + perfect-debounce@2.1.0: {} + + performance-now@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pidtree@0.6.0: {} + + pify@2.3.0: {} + + pify@3.0.0: {} + + pify@5.0.0: {} + + pirates@4.0.7: {} + + pkg-conf@2.1.0: + dependencies: + find-up: 2.1.0 + load-json-file: 4.0.0 + + png-js@1.0.0: {} + + polylabel@1.1.0: + dependencies: + tinyqueue: 2.0.3 + + possible-typed-array-names@1.1.0: {} + + postcss-attribute-case-insensitive@8.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-calc@10.1.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + postcss-clamp@4.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-color-functional-notation@8.0.1(postcss@8.5.6): + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + postcss-color-hex-alpha@11.0.0(postcss@8.5.6): + dependencies: + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-color-rebeccapurple@11.0.0(postcss@8.5.6): + dependencies: + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-colormin@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-convert-values@7.0.8(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-custom-media@12.0.0(postcss@8.5.6): + dependencies: + "@csstools/cascade-layer-name-parser": 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/media-query-list-parser": 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.6 + + postcss-custom-properties@15.0.0(postcss@8.5.6): + dependencies: + "@csstools/cascade-layer-name-parser": 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-custom-selectors@9.0.0(postcss@8.5.6): + dependencies: + "@csstools/cascade-layer-name-parser": 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-dir-pseudo-class@10.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-discard-comments@7.0.5(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-discard-duplicates@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-empty@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-overridden@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-double-position-gradients@7.0.0(postcss@8.5.6): + dependencies: + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-focus-visible@11.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-focus-within@10.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-font-variant@5.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-gap-properties@7.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-image-set-function@8.0.0(postcss@8.5.6): + dependencies: + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-import@15.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-import@16.1.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.6): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.6 + + postcss-lab-function@8.0.1(postcss@8.5.6): + dependencies: + "@csstools/css-color-parser": 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-tokenizer": 4.0.0 + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/utilities": 3.0.0(postcss@8.5.6) + postcss: 8.5.6 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.6 + yaml: 2.8.2 + + postcss-logical@9.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-merge-longhand@7.0.5(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + stylehacks: 7.0.7(postcss@8.5.6) + + postcss-merge-rules@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-minify-font-values@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@7.0.1(postcss@8.5.6): + dependencies: + colord: 2.9.3 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-params@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@7.0.5(postcss@8.5.6): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nested@6.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-nesting@14.0.0(postcss@8.5.6): + dependencies: + "@csstools/selector-resolve-nested": 4.0.0(postcss-selector-parser@7.1.1) + "@csstools/selector-specificity": 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-normalize-charset@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-normalize-display-values@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-opacity-percentage@3.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-ordered-values@7.0.2(postcss@8.5.6): + dependencies: + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-overflow-shorthand@7.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-page-break@3.0.4(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-place@11.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-preset-env@11.1.3(postcss@8.5.6): + dependencies: + "@csstools/postcss-alpha-function": 2.0.2(postcss@8.5.6) + "@csstools/postcss-cascade-layers": 6.0.0(postcss@8.5.6) + "@csstools/postcss-color-function": 5.0.1(postcss@8.5.6) + "@csstools/postcss-color-function-display-p3-linear": 2.0.1(postcss@8.5.6) + "@csstools/postcss-color-mix-function": 4.0.1(postcss@8.5.6) + "@csstools/postcss-color-mix-variadic-function-arguments": 2.0.1(postcss@8.5.6) + "@csstools/postcss-content-alt-text": 3.0.0(postcss@8.5.6) + "@csstools/postcss-contrast-color-function": 3.0.1(postcss@8.5.6) + "@csstools/postcss-exponential-functions": 3.0.0(postcss@8.5.6) + "@csstools/postcss-font-format-keywords": 5.0.0(postcss@8.5.6) + "@csstools/postcss-gamut-mapping": 3.0.1(postcss@8.5.6) + "@csstools/postcss-gradients-interpolation-method": 6.0.1(postcss@8.5.6) + "@csstools/postcss-hwb-function": 5.0.1(postcss@8.5.6) + "@csstools/postcss-ic-unit": 5.0.0(postcss@8.5.6) + "@csstools/postcss-initial": 3.0.0(postcss@8.5.6) + "@csstools/postcss-is-pseudo-class": 6.0.0(postcss@8.5.6) + "@csstools/postcss-light-dark-function": 3.0.0(postcss@8.5.6) + "@csstools/postcss-logical-float-and-clear": 4.0.0(postcss@8.5.6) + "@csstools/postcss-logical-overflow": 3.0.0(postcss@8.5.6) + "@csstools/postcss-logical-overscroll-behavior": 3.0.0(postcss@8.5.6) + "@csstools/postcss-logical-resize": 4.0.0(postcss@8.5.6) + "@csstools/postcss-logical-viewport-units": 4.0.0(postcss@8.5.6) + "@csstools/postcss-media-minmax": 3.0.0(postcss@8.5.6) + "@csstools/postcss-media-queries-aspect-ratio-number-values": 4.0.0(postcss@8.5.6) + "@csstools/postcss-mixins": 1.0.0(postcss@8.5.6) + "@csstools/postcss-nested-calc": 5.0.0(postcss@8.5.6) + "@csstools/postcss-normalize-display-values": 5.0.1(postcss@8.5.6) + "@csstools/postcss-oklab-function": 5.0.1(postcss@8.5.6) + "@csstools/postcss-position-area-property": 2.0.0(postcss@8.5.6) + "@csstools/postcss-progressive-custom-properties": 5.0.0(postcss@8.5.6) + "@csstools/postcss-property-rule-prelude-list": 2.0.0(postcss@8.5.6) + "@csstools/postcss-random-function": 3.0.0(postcss@8.5.6) + "@csstools/postcss-relative-color-syntax": 4.0.1(postcss@8.5.6) + "@csstools/postcss-scope-pseudo-class": 5.0.0(postcss@8.5.6) + "@csstools/postcss-sign-functions": 2.0.0(postcss@8.5.6) + "@csstools/postcss-stepped-value-functions": 5.0.0(postcss@8.5.6) + "@csstools/postcss-syntax-descriptor-syntax-production": 2.0.0(postcss@8.5.6) + "@csstools/postcss-system-ui-font-family": 2.0.0(postcss@8.5.6) + "@csstools/postcss-text-decoration-shorthand": 5.0.2(postcss@8.5.6) + "@csstools/postcss-trigonometric-functions": 5.0.0(postcss@8.5.6) + "@csstools/postcss-unset-value": 5.0.0(postcss@8.5.6) + autoprefixer: 10.4.24(postcss@8.5.6) + browserslist: 4.28.1 + css-blank-pseudo: 8.0.1(postcss@8.5.6) + css-has-pseudo: 8.0.0(postcss@8.5.6) + css-prefers-color-scheme: 11.0.0(postcss@8.5.6) + cssdb: 8.7.1 + postcss: 8.5.6 + postcss-attribute-case-insensitive: 8.0.0(postcss@8.5.6) + postcss-clamp: 4.1.0(postcss@8.5.6) + postcss-color-functional-notation: 8.0.1(postcss@8.5.6) + postcss-color-hex-alpha: 11.0.0(postcss@8.5.6) + postcss-color-rebeccapurple: 11.0.0(postcss@8.5.6) + postcss-custom-media: 12.0.0(postcss@8.5.6) + postcss-custom-properties: 15.0.0(postcss@8.5.6) + postcss-custom-selectors: 9.0.0(postcss@8.5.6) + postcss-dir-pseudo-class: 10.0.0(postcss@8.5.6) + postcss-double-position-gradients: 7.0.0(postcss@8.5.6) + postcss-focus-visible: 11.0.0(postcss@8.5.6) + postcss-focus-within: 10.0.0(postcss@8.5.6) + postcss-font-variant: 5.0.0(postcss@8.5.6) + postcss-gap-properties: 7.0.0(postcss@8.5.6) + postcss-image-set-function: 8.0.0(postcss@8.5.6) + postcss-lab-function: 8.0.1(postcss@8.5.6) + postcss-logical: 9.0.0(postcss@8.5.6) + postcss-nesting: 14.0.0(postcss@8.5.6) + postcss-opacity-percentage: 3.0.0(postcss@8.5.6) + postcss-overflow-shorthand: 7.0.0(postcss@8.5.6) + postcss-page-break: 3.0.4(postcss@8.5.6) + postcss-place: 11.0.0(postcss@8.5.6) + postcss-pseudo-class-any-link: 11.0.0(postcss@8.5.6) + postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.6) + postcss-selector-not: 9.0.0(postcss@8.5.6) + + postcss-pseudo-class-any-link@11.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-reduce-initial@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + postcss: 8.5.6 + + postcss-reduce-transforms@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-replace-overflow-wrap@4.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-reporter@7.1.0(postcss@8.5.6): + dependencies: + picocolors: 1.1.1 + postcss: 8.5.6 + thenby: 1.3.4 + + postcss-safe-parser@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-selector-not@9.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@7.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + svgo: 4.0.0 + + postcss-unique-selectors@7.0.4(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.1: + dependencies: + fast-diff: 1.3.0 + + prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3): + dependencies: + prettier: 3.8.1 + typescript: 5.9.3 + + prettier@2.8.8: + optional: true + + prettier@3.8.1: {} + + pretty-bytes@5.6.0: {} + + pretty-bytes@6.1.1: {} + + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + + process-nextick-args@2.0.1: {} + + proto-list@1.2.4: {} + + protocols@2.0.2: {} + + punycode@2.3.1: {} + + qified@0.6.0: + dependencies: + hookified: 1.15.1 + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + raf@3.4.1: + dependencies: + performance-now: 2.1.0 + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + read-package-up@11.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 9.0.1 + type-fest: 4.41.0 + + read-package-up@12.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 10.1.0 + type-fest: 5.4.4 + + read-pkg@10.1.0: + dependencies: + "@types/normalize-package-data": 2.4.4 + normalize-package-data: 8.0.0 + parse-json: 8.3.0 + type-fest: 5.4.4 + unicorn-magic: 0.4.0 + + read-pkg@9.0.1: + dependencies: + "@types/normalize-package-data": 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 8.3.0 + type-fest: 4.41.0 + unicorn-magic: 0.1.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regexpu-core@6.4.0: + 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 + + registry-auth-token@5.1.1: + dependencies: + "@pnpm/npm-conf": 3.0.2 + + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + + regression@2.0.1: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + require-main-filename@2.0.0: {} + + resolve-alpn@1.2.1: {} + + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@4.0.2: + dependencies: + lowercase-keys: 3.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rgbcolor@1.0.1: {} + + rollup@2.79.2: + optionalDependencies: + fsevents: 2.3.3 + + rollup@4.57.1: + dependencies: + "@types/estree": 1.0.8 + optionalDependencies: + "@rollup/rollup-android-arm-eabi": 4.57.1 + "@rollup/rollup-android-arm64": 4.57.1 + "@rollup/rollup-darwin-arm64": 4.57.1 + "@rollup/rollup-darwin-x64": 4.57.1 + "@rollup/rollup-freebsd-arm64": 4.57.1 + "@rollup/rollup-freebsd-x64": 4.57.1 + "@rollup/rollup-linux-arm-gnueabihf": 4.57.1 + "@rollup/rollup-linux-arm-musleabihf": 4.57.1 + "@rollup/rollup-linux-arm64-gnu": 4.57.1 + "@rollup/rollup-linux-arm64-musl": 4.57.1 + "@rollup/rollup-linux-loong64-gnu": 4.57.1 + "@rollup/rollup-linux-loong64-musl": 4.57.1 + "@rollup/rollup-linux-ppc64-gnu": 4.57.1 + "@rollup/rollup-linux-ppc64-musl": 4.57.1 + "@rollup/rollup-linux-riscv64-gnu": 4.57.1 + "@rollup/rollup-linux-riscv64-musl": 4.57.1 + "@rollup/rollup-linux-s390x-gnu": 4.57.1 + "@rollup/rollup-linux-x64-gnu": 4.57.1 + "@rollup/rollup-linux-x64-musl": 4.57.1 + "@rollup/rollup-openbsd-x64": 4.57.1 + "@rollup/rollup-openharmony-arm64": 4.57.1 + "@rollup/rollup-win32-arm64-msvc": 4.57.1 + "@rollup/rollup-win32-ia32-msvc": 4.57.1 + "@rollup/rollup-win32-x64-gnu": 4.57.1 + "@rollup/rollup-win32-x64-msvc": 4.57.1 + fsevents: 2.3.3 + + run-applescript@7.1.0: {} + + run-async@2.4.1: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + sax@1.4.4: {} + + semantic-release@25.0.3(typescript@5.9.3): + dependencies: + "@semantic-release/commit-analyzer": 13.0.1(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/error": 4.0.0 + "@semantic-release/github": 12.0.6(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/npm": 13.1.4(semantic-release@25.0.3(typescript@5.9.3)) + "@semantic-release/release-notes-generator": 14.1.0(semantic-release@25.0.3(typescript@5.9.3)) + aggregate-error: 5.0.0 + cosmiconfig: 9.0.0(typescript@5.9.3) + debug: 4.4.3 + env-ci: 11.2.0 + execa: 9.6.1 + figures: 6.1.0 + find-versions: 6.0.0 + get-stream: 6.0.1 + git-log-parser: 1.2.1 + hook-std: 4.0.0 + hosted-git-info: 9.0.2 + import-from-esm: 2.0.0 + lodash-es: 4.17.23 + marked: 15.0.12 + marked-terminal: 7.3.0(marked@15.0.12) + micromatch: 4.0.8 + p-each-series: 3.0.0 + p-reduce: 3.0.0 + read-package-up: 12.0.0 + resolve-from: 5.0.0 + semver: 7.7.4 + signale: 1.4.0 + yargs: 18.0.0 + transitivePeerDependencies: + - supports-color + - typescript + + semver-regex@4.0.5: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.34.5: + dependencies: + "@img/colour": 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + "@img/sharp-darwin-arm64": 0.34.5 + "@img/sharp-darwin-x64": 0.34.5 + "@img/sharp-libvips-darwin-arm64": 1.2.4 + "@img/sharp-libvips-darwin-x64": 1.2.4 + "@img/sharp-libvips-linux-arm": 1.2.4 + "@img/sharp-libvips-linux-arm64": 1.2.4 + "@img/sharp-libvips-linux-ppc64": 1.2.4 + "@img/sharp-libvips-linux-riscv64": 1.2.4 + "@img/sharp-libvips-linux-s390x": 1.2.4 + "@img/sharp-libvips-linux-x64": 1.2.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.2.4 + "@img/sharp-libvips-linuxmusl-x64": 1.2.4 + "@img/sharp-linux-arm": 0.34.5 + "@img/sharp-linux-arm64": 0.34.5 + "@img/sharp-linux-ppc64": 0.34.5 + "@img/sharp-linux-riscv64": 0.34.5 + "@img/sharp-linux-s390x": 0.34.5 + "@img/sharp-linux-x64": 0.34.5 + "@img/sharp-linuxmusl-arm64": 0.34.5 + "@img/sharp-linuxmusl-x64": 0.34.5 + "@img/sharp-wasm32": 0.34.5 + "@img/sharp-win32-arm64": 0.34.5 + "@img/sharp-win32-ia32": 0.34.5 + "@img/sharp-win32-x64": 0.34.5 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + signale@1.4.0: + dependencies: + chalk: 2.4.2 + figures: 2.0.0 + pkg-conf: 2.1.0 + + sirv@3.0.2: + dependencies: + "@polka/url": 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + + slash@5.1.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + smob@1.6.1: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + sourcemap-codec@1.4.8: {} + + spawn-error-forwarder@1.0.0: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.22 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-license-ids@3.0.22: {} + + split2@1.0.0: + dependencies: + through2: 2.0.5 + + split2@4.2.0: {} + + stackblur-canvas@2.7.0: {} + + stencil-wormhole@3.4.1: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-object@3.3.0: + dependencies: + get-own-enumerable-property-symbols: 3.0.2 + is-obj: 1.0.1 + is-regexp: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-comments@2.0.1: {} + + strip-final-newline@2.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-final-newline@4.0.0: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + style-mod@4.1.3: {} + + stylehacks@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + stylelint-config-recommended@18.0.0(stylelint@17.3.0(typescript@5.9.3)): + dependencies: + stylelint: 17.3.0(typescript@5.9.3) + + stylelint-config-standard@40.0.0(stylelint@17.3.0(typescript@5.9.3)): + dependencies: + stylelint: 17.3.0(typescript@5.9.3) + stylelint-config-recommended: 18.0.0(stylelint@17.3.0(typescript@5.9.3)) + + stylelint@17.3.0(typescript@5.9.3): + dependencies: + "@csstools/css-calc": 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/css-parser-algorithms": 4.0.0(@csstools/css-tokenizer@4.0.0) + "@csstools/css-syntax-patches-for-csstree": 1.0.27 + "@csstools/css-tokenizer": 4.0.0 + "@csstools/media-query-list-parser": 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + "@csstools/selector-resolve-nested": 4.0.0(postcss-selector-parser@7.1.1) + "@csstools/selector-specificity": 6.0.0(postcss-selector-parser@7.1.1) + balanced-match: 3.0.1 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.9.3) + css-functions-list: 3.3.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.2 + global-modules: 2.0.0 + globby: 16.1.1 + globjoin: 0.1.4 + html-tags: 5.1.0 + ignore: 7.0.5 + import-meta-resolve: 4.2.0 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.37.0 + mathml-tag-names: 4.0.0 + meow: 14.0.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + string-width: 8.2.0 + supports-hyperlinks: 4.4.0 + svg-tags: 1.0.0 + table: 6.9.0 + write-file-atomic: 7.0.0 + transitivePeerDependencies: + - supports-color + - typescript + + sucrase@3.35.1: + dependencies: + "@jridgewell/gen-mapping": 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + + super-regex@1.1.0: + dependencies: + function-timeout: 1.0.2 + make-asynchronous: 1.0.1 + time-span: 5.1.0 + + supports-color@10.2.2: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-hyperlinks@4.4.0: + dependencies: + has-flag: 5.0.1 + supports-color: 10.2.2 + + supports-preserve-symlinks-flag@1.0.0: {} + + svg-tags@1.0.0: {} + + svgo@4.0.0: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.4.4 + + synckit@0.11.12: + dependencies: + "@pkgr/core": 0.2.9 + + table@6.9.0: + dependencies: + ajv: 8.18.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tagged-tag@1.0.0: {} + + tailwindcss@3.4.19(yaml@2.8.2): + dependencies: + "@alloc/quick-lru": 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + temp-dir@2.0.0: {} + + temp-dir@3.0.0: {} + + tempy@0.6.0: + dependencies: + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + + tempy@3.2.0: + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + + terser@5.46.0: + dependencies: + "@jridgewell/source-map": 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + thenby@1.3.4: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through@2.3.8: {} + + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + + tiny-inflate@1.0.3: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyqueue@2.0.3: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + tr46@0.0.3: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + traverse@0.6.8: {} + + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tunnel@0.0.6: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.16.0: {} + + type-fest@0.21.3: {} + + type-fest@1.4.0: {} + + type-fest@2.19.0: {} + + type-fest@4.41.0: {} + + type-fest@5.4.4: + dependencies: + tagged-tag: 1.0.0 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3): + dependencies: + "@typescript-eslint/eslint-plugin": 8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + "@typescript-eslint/parser": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + "@typescript-eslint/typescript-estree": 8.56.0(typescript@5.9.3) + "@typescript-eslint/utils": 8.56.0(eslint@10.0.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 10.0.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + uglify-js@3.19.3: + optional: true + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@7.14.0: {} + + undici@6.23.0: {} + + undici@7.22.0: {} + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-emoji-modifier-base@1.0.0: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-property-aliases-ecmascript@2.2.0: {} + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: {} + + unicorn-magic@0.4.0: {} + + unique-string@2.0.0: + dependencies: + crypto-random-string: 2.0.0 + + unique-string@3.0.0: + dependencies: + crypto-random-string: 4.0.0 + + universal-user-agent@7.0.3: {} + + universalify@2.0.1: {} + + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + + upath@1.2.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + url-join@4.0.1: {} + + url-join@5.0.0: {} + + util-deprecate@1.0.2: {} + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + vite-dev-rpc@1.1.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + birpc: 2.9.0 + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + vite-hot-client: 2.1.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + + vite-hot-client@2.1.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + + vite-plugin-codeigniter@2.0.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + glob: 11.1.0 + picocolors: 1.1.1 + sharp: 0.34.5 + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + vite-plugin-static-copy: 3.2.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + zod: 4.3.6 + + vite-plugin-inspect@11.3.3(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + ansis: 4.2.0 + debug: 4.4.3 + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + vite-dev-rpc: 1.1.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)) + transitivePeerDependencies: + - supports-color + + vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2))(workbox-build@7.4.0)(workbox-window@7.4.0): + dependencies: + debug: 4.4.3 + pretty-bytes: 6.1.1 + tinyglobby: 0.2.15 + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + workbox-build: 7.4.0 + workbox-window: 7.4.0 + transitivePeerDependencies: + - supports-color + + vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2)): + dependencies: + chokidar: 3.6.0 + p-map: 7.0.4 + picocolors: 1.1.1 + tinyglobby: 0.2.15 + vite: 7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2) + + vite@7.3.1(@types/node@24.7.0)(jiti@1.21.7)(terser@5.46.0)(yaml@2.8.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + "@types/node": 24.7.0 + fsevents: 2.3.3 + jiti: 1.21.7 + terser: 5.46.0 + yaml: 2.8.2 + + w3c-keyname@2.2.8: {} + + wavesurfer.js@7.12.1: {} + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + web-worker@1.2.0: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@4.0.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.20 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-module@2.0.1: {} + + which-typed-array@1.1.20: + 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 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wordwrap@1.0.0: {} + + workbox-background-sync@7.4.0: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.0 + + workbox-broadcast-update@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-build@7.4.0: + dependencies: + "@apideck/better-ajv-errors": 0.3.6(ajv@8.18.0) + "@babel/core": 7.29.0 + "@babel/preset-env": 7.29.0(@babel/core@7.29.0) + "@babel/runtime": 7.28.6 + "@rollup/plugin-babel": 5.3.1(@babel/core@7.29.0)(rollup@2.79.2) + "@rollup/plugin-node-resolve": 15.3.1(rollup@2.79.2) + "@rollup/plugin-replace": 2.4.2(rollup@2.79.2) + "@rollup/plugin-terser": 0.4.4(rollup@2.79.2) + "@surma/rollup-plugin-off-main-thread": 2.2.3 + ajv: 8.18.0 + common-tags: 1.8.2 + fast-json-stable-stringify: 2.1.0 + fs-extra: 9.1.0 + glob: 11.1.0 + lodash: 4.17.23 + pretty-bytes: 5.6.0 + rollup: 2.79.2 + source-map: 0.8.0-beta.0 + stringify-object: 3.3.0 + strip-comments: 2.0.1 + tempy: 0.6.0 + upath: 1.2.0 + workbox-background-sync: 7.4.0 + workbox-broadcast-update: 7.4.0 + workbox-cacheable-response: 7.4.0 + workbox-core: 7.4.0 + workbox-expiration: 7.4.0 + workbox-google-analytics: 7.4.0 + workbox-navigation-preload: 7.4.0 + workbox-precaching: 7.4.0 + workbox-range-requests: 7.4.0 + workbox-recipes: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + workbox-streams: 7.4.0 + workbox-sw: 7.4.0 + workbox-window: 7.4.0 + transitivePeerDependencies: + - "@types/babel__core" + - supports-color + + workbox-cacheable-response@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-core@7.4.0: {} + + workbox-expiration@7.4.0: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.0 + + workbox-google-analytics@7.4.0: + dependencies: + workbox-background-sync: 7.4.0 + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-navigation-preload@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-precaching@7.4.0: + dependencies: + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-range-requests@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-recipes@7.4.0: + dependencies: + workbox-cacheable-response: 7.4.0 + workbox-core: 7.4.0 + workbox-expiration: 7.4.0 + workbox-precaching: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-routing@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-strategies@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-streams@7.4.0: + dependencies: + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + + workbox-sw@7.4.0: {} + + workbox-window@7.4.0: + dependencies: + "@types/trusted-types": 2.0.7 + workbox-core: 7.4.0 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + wrappy@1.0.2: {} + + write-file-atomic@7.0.0: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + + xml-formatter@3.6.7: + dependencies: + xml-parser-xo: 4.1.5 + + xml-parser-xo@4.1.5: {} + + xmldoc@2.0.3: + dependencies: + sax: 1.4.4 + + xtend@4.0.2: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.8.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs-parser@22.0.0: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + + yocto-queue@0.1.0: {} + + yoctocolors@2.1.2: {} + + zod@4.3.6: {} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 00000000..ec20059e --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,19 @@ +/* eslint-disable */ + +module.exports = { + plugins: [ + require("postcss-reporter"), + require("tailwindcss"), + require("postcss-preset-env")({ + stage: 4, + features: { "nesting-rules": false }, + }), + ...(process.env.NODE_ENV === "production" + ? [ + require("cssnano")({ + preset: "default", + }), + ] + : []), + ], +}; diff --git a/postcss.config.js b/postcss.config.js deleted file mode 100644 index f2f8cb17..00000000 --- a/postcss.config.js +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable */ - -module.exports = { - plugins: [ - require("postcss-import"), - require("tailwindcss"), - require("postcss-preset-env")({ stage: 1 }), - ...(process.env.NODE_ENV === "production" - ? [ - require("cssnano")({ - preset: "default", - }), - ] - : []), - ], -}; diff --git a/preload.php b/preload.php new file mode 100644 index 00000000..5e9937cf --- /dev/null +++ b/preload.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +/* + *--------------------------------------------------------------- + * Sample file for Preloading + *--------------------------------------------------------------- + * See https://www.php.net/manual/en/opcache.preloading.php + * + * How to Use: + * 0. Copy this file to your project root folder. + * 1. Set the $paths property of the preload class below. + * 2. Set opcache.preload in php.ini. + * php.ini: + * opcache.preload=/path/to/preload.php + */ + +// Load the paths config file +require __DIR__ . '/app/Config/Paths.php'; + +// Path to the front controller +define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); + +class preload +{ + /** + * @var array Paths to preload. + */ + private array $paths = [ + [ + 'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation + 'exclude' => [ + // Not needed if you don't use them. + '/system/Database/OCI8/', + '/system/Database/Postgre/', + '/system/Database/SQLite3/', + '/system/Database/SQLSRV/', + // Not needed for web apps. + '/system/Database/Seeder.php', + '/system/Test/', + '/system/CLI/', + '/system/Commands/', + '/system/Publisher/', + '/system/ComposerScripts.php', + // Not Class/Function files. + '/system/Config/Routes.php', + '/system/Language/', + '/system/bootstrap.php', + '/system/util_bootstrap.php', + '/system/rewrite.php', + '/Views/', + // Errors occur. + '/system/ThirdParty/', + ], + ], + ]; + + public function __construct() + { + $this->loadAutoloader(); + } + + /** + * Load PHP files. + */ + public function load(): void + { + foreach ($this->paths as $path) { + $directory = new RecursiveDirectoryIterator($path['include']); + $fullTree = new RecursiveIteratorIterator($directory); + $phpFiles = new RegexIterator($fullTree, '/.+((? $file) { + foreach ($path['exclude'] as $exclude) { + if (str_contains($file[0], $exclude)) { + continue 2; + } + } + + require_once $file[0]; + // Uncomment only for debugging (to inspect which files are included). + // Never use this in production - preload scripts must not generate output. + // echo 'Loaded: ' . $file[0] . "\n"; + } + } + } + + private function loadAutoloader(): void + { + $paths = new Paths(); + require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; + + Boot::preload($paths); + } +} + +(new preload())->load(); diff --git a/public/.htaccess b/public/.htaccess index a5d6c2a5..396272bc 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -1,5 +1,5 @@ # Disable directory browsing -Options All -Indexes +Options -Indexes # ---------------------------------------------------------------------- # Rewrite engine @@ -11,7 +11,7 @@ Options All -Indexes Options +FollowSymlinks RewriteEngine On - # If you installed CodeIgniter in a subfolder, you will need to + # If you installed Castopod in a subfolder, you will need to # change the following line to match the subfolder you need. # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase # RewriteBase / @@ -31,7 +31,7 @@ Options All -Indexes # request to the front controller, index.php RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA] + RewriteRule ^([\s\S]*)$ index.php?/$1 [L,NC,QSA] # Ensure Authorization header is passed along RewriteCond %{HTTP:Authorization} . @@ -45,5 +45,5 @@ Options All -Indexes # Disable server signature start - ServerSignature Off +ServerSignature Off # Disable server signature end diff --git a/public/.well-known/GDPR.yml b/public/.well-known/GDPR.yml new file mode 100644 index 00000000..dba6d271 --- /dev/null +++ b/public/.well-known/GDPR.yml @@ -0,0 +1,86 @@ +# This file lists processing purposes and the personal data gathered by +# Castopod. +# It is intended for hosting providers who want to provide a service +# based on Castopod, helping them to comply with GDPR requirements. Note +# that the services powered by Castopod may collect more data, HTTP logs +# in particular. As a hosting provider, you must inform your users of their +# rights and how their data are used and protected. + +purposes: + - description: | + Deduplicate number of audio file downloads made by the same listener for + analytics purposes + lawfulness: legitimate interest + data: + - field: (User IP address + Browser User Agent) + required: yes + visibility: none + description: | + In order to produce analytics data comparable to the podcasting + ecosystem standards, the User IP address (REMOTE_ADDR) with the + browser User Agent (HTTP_USER_AGENT) are stored when an audio file + is downloaded. + mitigation: | + The data (User IP address + Browser User Agent) is never stored in + plain format. + The data is concatenated with a cryptographic salt, the current date, + and the podcast or episode IDs. + The data is hashed (using sha1) after being concatenated and before + being stored. + The data is stored in a cache database (eg. Redis). + The data expires every day at midnight (server time). + retention: 24 hours maximum + + - description: Connect users to their accounts + lawfulness: legitimate interest + data: + - field: username + required: yes + visibility: authenticated users + description: | + The username is used to identify users during the login process. + The username is only required for users accessing the admin area. + mitigation: The username does not have to be a real or known identity. + retention: forever + + - field: user e-mail address + required: yes + visibility: administrators + description: | + The e-mail address is used for administrative purposes, to identify users + during the login process and in case of forgotten password. + retention: forever + + - field: password + required: yes + visibility: private + description: | + The password is used to check the identity of users during the login + process. + mitigation: | + Only hashes (using the Argon2 key derivation function) of the passwords + are stored in the database (but they transit over the network). + retention: forever + + - description: Claim ownership of a podcast + lawfulness: legitimate interest + data: + - field: Podcast e-mail address + required: yes + visibility: public + description: | + The podcast e-mail address is used to claim podcast ownership on other + platforms (such as Apple Podcasts). + mitigation: The e-mail can be generic. + retention: forever + - description: Grant access to premium content + lawfulness: legitimate interest + data: + - field: Subscriber's email address + required: yes + visibility: administrators + description: | + The subscriber's e-mail address is used to provide credentials for + listening to premium content. + mitigation: The e-mail can be generic. + retention: until the subscription ends diff --git a/public/favicon.ico b/public/favicon.ico index b844d1d0..9bf9b97a 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/icon-180.png b/public/icon-180.png new file mode 100644 index 00000000..937c4c6c Binary files /dev/null and b/public/icon-180.png differ diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 00000000..7864f7e9 Binary files /dev/null and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 00000000..9998e36a Binary files /dev/null and b/public/icon-512.png differ diff --git a/public/icon-64.png b/public/icon-64.png new file mode 100644 index 00000000..cf8d2cf1 Binary files /dev/null and b/public/icon-64.png differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 00000000..3c182ad4 Binary files /dev/null and b/public/icon.png differ diff --git a/public/index.php b/public/index.php index 4d04f8a5..070db6ca 100644 --- a/public/index.php +++ b/public/index.php @@ -2,11 +2,43 @@ declare(strict_types=1); +use CodeIgniter\Boot; use Config\Paths; +/* + *--------------------------------------------------------------- + * CHECK PHP VERSION + *--------------------------------------------------------------- + */ + +$minPhpVersion = '8.5'; // If you update this, don't forget to update `spark`. +if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { + $message = sprintf( + 'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s', + $minPhpVersion, + PHP_VERSION, + ); + + header('HTTP/1.1 503 Service Unavailable.', true, 503); + echo $message; + + exit(1); +} + +/* + *--------------------------------------------------------------- + * SET THE CURRENT DIRECTORY + *--------------------------------------------------------------- + */ + // Path to the front controller (this file) define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR); +// Ensure the current directory is pointing to the front controller's directory +if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) { + chdir(FCPATH); +} + /* *--------------------------------------------------------------- * BOOTSTRAP THE APPLICATION @@ -16,26 +48,14 @@ define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR); * and fires up an environment-specific bootstrapping. */ -// Ensure the current directory is pointing to the front controller's directory -chdir(__DIR__); - -// Load our paths config file +// LOAD OUR PATHS CONFIG FILE // This is the line that might need to be changed, depending on your folder structure. -$pathsConfig = FCPATH . '../app/Config/Paths.php'; -// ^^^ Change this if you move your application folder -require realpath($pathsConfig) ?: $pathsConfig; +require FCPATH . '../app/Config/Paths.php'; +// ^^^ Change this line if you move your application folder $paths = new Paths(); -// Location of the framework bootstrap file. -$bootstrap = rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; -$app = require realpath($bootstrap) ?: $bootstrap; +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; -/* - *--------------------------------------------------------------- - * LAUNCH THE APPLICATION - *--------------------------------------------------------------- - * Now that everything is setup, it's time to actually fire - * up the engines and make this app do its thang. - */ -$app->run(); +exit(Boot::bootWeb($paths)); diff --git a/public/media/index.html b/public/media/index.html index eebf8ecb..cf672743 100644 --- a/public/media/index.html +++ b/public/media/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/public/media/persons/index.html b/public/media/persons/index.html index e69de29b..cf672743 100644 --- a/public/media/persons/index.html +++ b/public/media/persons/index.html @@ -0,0 +1,9 @@ + + + + 403 Forbidden + + +

    Directory access is forbidden.

    + + diff --git a/public/media/podcasts/index.html b/public/media/podcasts/index.html index eebf8ecb..cf672743 100644 --- a/public/media/podcasts/index.html +++ b/public/media/podcasts/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/public/media/site/index.html b/public/media/site/index.html new file mode 100644 index 00000000..e69de29b diff --git a/rector.php b/rector.php index e3ba7ecf..9fb15216 100644 --- a/rector.php +++ b/rector.php @@ -2,79 +2,58 @@ declare(strict_types=1); -use Rector\CodingStyle\Rector\ClassMethod\UnSpreadOperatorRector; +use Rector\CodeQuality\Rector\ClassMethod\ExplicitReturnNullRector; use Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector; -use Rector\CodingStyle\Rector\FuncCall\ConsistentPregDelimiterRector; -use Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector; -use Rector\Core\Configuration\Option; -use Rector\Core\ValueObject\PhpVersion; +use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; +use Rector\CodingStyle\Rector\String_\SimplifyQuoteEscapeRector; +use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; +use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector; use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector; -use Rector\EarlyReturn\Rector\If_\ChangeOrIfReturnToEarlyReturnRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; -use Rector\Php80\Rector\ClassMethod\OptionalParametersAfterRequiredRector; -use Rector\Set\ValueObject\SetList; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; +use Rector\ValueObject\PhpVersion; -return static function (ContainerConfigurator $containerConfigurator): void { - // get parameters - $parameters = $containerConfigurator->parameters(); +return RectorConfig::configure() + ->withPaths([__DIR__ . '/app', __DIR__ . '/modules', __DIR__ . '/tests', __DIR__ . '/public']) + ->withBootstrapFiles([__DIR__ . '/vendor/codeigniter4/framework/system/Test/bootstrap.php']) + ->withPhpVersion(PhpVersion::PHP_85) + ->withPhpSets(php85: true) + ->withPreparedSets( + typeDeclarations: true, + codeQuality: true, + codingStyle: true, + earlyReturn: true, + deadCode: true, + ) + ->withImportNames(true, true, true, true) + ->withSkip([ + // .mp3 files were somehow processed by rector, so skip all media files + __DIR__ . '/public/media/*', - $parameters->set(Option::PATHS, [ - __DIR__ . '/app', - __DIR__ . '/tests', - __DIR__ . '/public', - ]); + __DIR__ . '/app/Views/errors/*', - // do you need to include constants, class aliases or custom autoloader? files listed will be executed - $parameters->set(Option::BOOTSTRAP_FILES, [ - __DIR__ . '/vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php', - ]); - - // Define what rule sets will be applied - $containerConfigurator->import(SetList::PHP_80); - $containerConfigurator->import(SetList::TYPE_DECLARATION); - $containerConfigurator->import(SetList::TYPE_DECLARATION_STRICT); - $containerConfigurator->import(SetList::CODE_QUALITY); - $containerConfigurator->import(SetList::CODING_STYLE); - $containerConfigurator->import(SetList::EARLY_RETURN); - $containerConfigurator->import(SetList::DEAD_CODE); - $containerConfigurator->import(SetList::ORDER); - - // auto import fully qualified class names - $parameters->set(Option::AUTO_IMPORT_NAMES, true); - // $parameters->set(Option::ENABLE_CACHE, true); - $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_80); - - $parameters->set(Option::SKIP, [ // skip specific generated files - __DIR__ . '/app/Language/*/PersonsTaxonomy.php', + __DIR__ . '/modules/Admin/Language/*/PersonsTaxonomy.php', // skip rules from used sets - ChangeOrIfReturnToEarlyReturnRector::class, ChangeOrIfContinueToMultiContinueRector::class, EncapsedStringsToSprintfRector::class, - SplitStringClassConstantToClassConstFetchRector::class, - UnSpreadOperatorRector::class, + RemoveExtraParametersRector::class, + UnwrapFutureCompatibleIfPhpVersionRector::class, + ExplicitReturnNullRector::class, // skip rule in specific directory StringClassNameToClassConstantRector::class => [ __DIR__ . '/app/Language/*', + __DIR__ . '/modules/*/Language/*', ], - OptionalParametersAfterRequiredRector::class => [ - __DIR__ . '/app/Validation', - ], - ]); + SimplifyQuoteEscapeRector::class => [__DIR__ . '/app/Language/*', __DIR__ . '/modules/*/Language/*'], - // Path to phpstan with extensions, that PHPSTan in Rector uses to determine types - $parameters->set( - Option::PHPSTAN_FOR_RECTOR_PATH, - __DIR__ . '/phpstan.neon', - ); + NewlineAfterStatementRector::class => [__DIR__ . '/app/Views'], - $services = $containerConfigurator->services(); - $services->set(ConsistentPregDelimiterRector::class)->call('configure', [ - [ - ConsistentPregDelimiterRector::DELIMITER => '~', + RemoveUnreachableStatementRector::class => [ + __DIR__ . '/modules/Install/Controllers/InstallController.php', ], - ]); -}; + ]) + ->withPHPStanConfigs([__DIR__ . '/phpstan.neon', 'vendor/codeigniter/phpstan-codeigniter/extension.neon']); diff --git a/resources/icons/custom/_index.php b/resources/icons/custom/_index.php new file mode 100644 index 00000000..0ef2821e --- /dev/null +++ b/resources/icons/custom/_index.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/resources/icons/funding/_index.php b/resources/icons/funding/_index.php new file mode 100644 index 00000000..f939dcca --- /dev/null +++ b/resources/icons/funding/_index.php @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/resources/icons/funding/default.svg b/resources/icons/funding/default.svg new file mode 100644 index 00000000..7dd88909 --- /dev/null +++ b/resources/icons/funding/default.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/donorbox.svg b/resources/icons/funding/donorbox.svg new file mode 100644 index 00000000..a9102a6f --- /dev/null +++ b/resources/icons/funding/donorbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/gofundme.svg b/resources/icons/funding/gofundme.svg new file mode 100755 index 00000000..5cee4579 --- /dev/null +++ b/resources/icons/funding/gofundme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/helloasso.svg b/resources/icons/funding/helloasso.svg new file mode 100755 index 00000000..381aefef --- /dev/null +++ b/resources/icons/funding/helloasso.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/indiegogo.svg b/resources/icons/funding/indiegogo.svg new file mode 100755 index 00000000..6cad95a0 --- /dev/null +++ b/resources/icons/funding/indiegogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/kickstarter.svg b/resources/icons/funding/kickstarter.svg new file mode 100755 index 00000000..9be7ebac --- /dev/null +++ b/resources/icons/funding/kickstarter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/kisskissbankbank.svg b/resources/icons/funding/kisskissbankbank.svg new file mode 100755 index 00000000..aafd6f4c --- /dev/null +++ b/resources/icons/funding/kisskissbankbank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/kofi.svg b/resources/icons/funding/kofi.svg new file mode 100644 index 00000000..0bcbc636 --- /dev/null +++ b/resources/icons/funding/kofi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/liberapay.svg b/resources/icons/funding/liberapay.svg new file mode 100755 index 00000000..79b03686 --- /dev/null +++ b/resources/icons/funding/liberapay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/patreon.svg b/resources/icons/funding/patreon.svg new file mode 100755 index 00000000..0bf9b7f0 --- /dev/null +++ b/resources/icons/funding/patreon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/paypal.svg b/resources/icons/funding/paypal.svg new file mode 100755 index 00000000..9f3be76a --- /dev/null +++ b/resources/icons/funding/paypal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/tipeee.svg b/resources/icons/funding/tipeee.svg new file mode 100755 index 00000000..0c346332 --- /dev/null +++ b/resources/icons/funding/tipeee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/funding/ulule.svg b/resources/icons/funding/ulule.svg new file mode 100755 index 00000000..72f1a65a --- /dev/null +++ b/resources/icons/funding/ulule.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/_index.php b/resources/icons/podcasting/_index.php new file mode 100644 index 00000000..562854ec --- /dev/null +++ b/resources/icons/podcasting/_index.php @@ -0,0 +1,48 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/antennapod.svg b/resources/icons/podcasting/antennapod.svg new file mode 100755 index 00000000..044712e6 --- /dev/null +++ b/resources/icons/podcasting/antennapod.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/anytime.svg b/resources/icons/podcasting/anytime.svg new file mode 100644 index 00000000..14f22a8b --- /dev/null +++ b/resources/icons/podcasting/anytime.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/apple.svg b/resources/icons/podcasting/apple.svg new file mode 100755 index 00000000..74f3efc7 --- /dev/null +++ b/resources/icons/podcasting/apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/blubrry.svg b/resources/icons/podcasting/blubrry.svg new file mode 100755 index 00000000..ca2a4da4 --- /dev/null +++ b/resources/icons/podcasting/blubrry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/breaker.svg b/resources/icons/podcasting/breaker.svg new file mode 100755 index 00000000..d4447648 --- /dev/null +++ b/resources/icons/podcasting/breaker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/breez.svg b/resources/icons/podcasting/breez.svg new file mode 100644 index 00000000..905542ac --- /dev/null +++ b/resources/icons/podcasting/breez.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/castamatic.svg b/resources/icons/podcasting/castamatic.svg new file mode 100644 index 00000000..e0914121 --- /dev/null +++ b/resources/icons/podcasting/castamatic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/castbox.svg b/resources/icons/podcasting/castbox.svg new file mode 100755 index 00000000..c9f27fae --- /dev/null +++ b/resources/icons/podcasting/castbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/castopod.svg b/resources/icons/podcasting/castopod.svg new file mode 100755 index 00000000..b0d4374d --- /dev/null +++ b/resources/icons/podcasting/castopod.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/castro.svg b/resources/icons/podcasting/castro.svg new file mode 100755 index 00000000..0e075b05 --- /dev/null +++ b/resources/icons/podcasting/castro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/deezer.svg b/resources/icons/podcasting/deezer.svg new file mode 100755 index 00000000..bcd3b7b3 --- /dev/null +++ b/resources/icons/podcasting/deezer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/default.svg b/resources/icons/podcasting/default.svg new file mode 100644 index 00000000..6437d60d --- /dev/null +++ b/resources/icons/podcasting/default.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/episodes-fm.svg b/resources/icons/podcasting/episodes-fm.svg new file mode 100644 index 00000000..e5ed1e34 --- /dev/null +++ b/resources/icons/podcasting/episodes-fm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/fountain.svg b/resources/icons/podcasting/fountain.svg new file mode 100644 index 00000000..796047e7 --- /dev/null +++ b/resources/icons/podcasting/fountain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/fyyd.svg b/resources/icons/podcasting/fyyd.svg new file mode 100755 index 00000000..696d4983 --- /dev/null +++ b/resources/icons/podcasting/fyyd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/google.svg b/resources/icons/podcasting/google.svg new file mode 100755 index 00000000..ecd0e555 --- /dev/null +++ b/resources/icons/podcasting/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/gpodder.svg b/resources/icons/podcasting/gpodder.svg new file mode 100644 index 00000000..b2b4b86d --- /dev/null +++ b/resources/icons/podcasting/gpodder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/ivoox.svg b/resources/icons/podcasting/ivoox.svg new file mode 100755 index 00000000..8cd43cb6 --- /dev/null +++ b/resources/icons/podcasting/ivoox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/listennotes.svg b/resources/icons/podcasting/listennotes.svg new file mode 100755 index 00000000..f5336785 --- /dev/null +++ b/resources/icons/podcasting/listennotes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/overcast.svg b/resources/icons/podcasting/overcast.svg new file mode 100755 index 00000000..0fef49c4 --- /dev/null +++ b/resources/icons/podcasting/overcast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/playerfm.svg b/resources/icons/podcasting/playerfm.svg new file mode 100755 index 00000000..fe15dc7a --- /dev/null +++ b/resources/icons/podcasting/playerfm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/plink.svg b/resources/icons/podcasting/plink.svg new file mode 100644 index 00000000..f300d7b2 --- /dev/null +++ b/resources/icons/podcasting/plink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/pocketcasts.svg b/resources/icons/podcasting/pocketcasts.svg new file mode 100755 index 00000000..1815c259 --- /dev/null +++ b/resources/icons/podcasting/pocketcasts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podbean.svg b/resources/icons/podcasting/podbean.svg new file mode 100755 index 00000000..dc522606 --- /dev/null +++ b/resources/icons/podcasting/podbean.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podcastaddict.svg b/resources/icons/podcasting/podcastaddict.svg new file mode 100755 index 00000000..c16a756d --- /dev/null +++ b/resources/icons/podcasting/podcastaddict.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podcastguru.svg b/resources/icons/podcasting/podcastguru.svg new file mode 100644 index 00000000..ea61e070 --- /dev/null +++ b/resources/icons/podcasting/podcastguru.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podcastindex.svg b/resources/icons/podcasting/podcastindex.svg new file mode 100755 index 00000000..40659726 --- /dev/null +++ b/resources/icons/podcasting/podcastindex.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podchaser.svg b/resources/icons/podcasting/podchaser.svg new file mode 100755 index 00000000..f3fd817b --- /dev/null +++ b/resources/icons/podcasting/podchaser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podcloud.svg b/resources/icons/podcasting/podcloud.svg new file mode 100755 index 00000000..ab39751b --- /dev/null +++ b/resources/icons/podcasting/podcloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podfriend.svg b/resources/icons/podcasting/podfriend.svg new file mode 100755 index 00000000..026b66af --- /dev/null +++ b/resources/icons/podcasting/podfriend.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podinstall.svg b/resources/icons/podcasting/podinstall.svg new file mode 100755 index 00000000..773cef9b --- /dev/null +++ b/resources/icons/podcasting/podinstall.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podlink.svg b/resources/icons/podcasting/podlink.svg new file mode 100755 index 00000000..44c9abfb --- /dev/null +++ b/resources/icons/podcasting/podlink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podlp.svg b/resources/icons/podcasting/podlp.svg new file mode 100644 index 00000000..55fcc6a1 --- /dev/null +++ b/resources/icons/podcasting/podlp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podnews.svg b/resources/icons/podcasting/podnews.svg new file mode 100644 index 00000000..fd9302c8 --- /dev/null +++ b/resources/icons/podcasting/podnews.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podtail.svg b/resources/icons/podcasting/podtail.svg new file mode 100755 index 00000000..222d9086 --- /dev/null +++ b/resources/icons/podcasting/podtail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/podverse.svg b/resources/icons/podcasting/podverse.svg new file mode 100755 index 00000000..e823ae45 --- /dev/null +++ b/resources/icons/podcasting/podverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/radiopublic.svg b/resources/icons/podcasting/radiopublic.svg new file mode 100755 index 00000000..5c6e8893 --- /dev/null +++ b/resources/icons/podcasting/radiopublic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/sphinxchat.svg b/resources/icons/podcasting/sphinxchat.svg new file mode 100644 index 00000000..b02f3575 --- /dev/null +++ b/resources/icons/podcasting/sphinxchat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/spotify.svg b/resources/icons/podcasting/spotify.svg new file mode 100755 index 00000000..2068709c --- /dev/null +++ b/resources/icons/podcasting/spotify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/spreaker.svg b/resources/icons/podcasting/spreaker.svg new file mode 100755 index 00000000..dcb7573f --- /dev/null +++ b/resources/icons/podcasting/spreaker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/stitcher.svg b/resources/icons/podcasting/stitcher.svg new file mode 100755 index 00000000..50541d55 --- /dev/null +++ b/resources/icons/podcasting/stitcher.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/truefans.svg b/resources/icons/podcasting/truefans.svg new file mode 100644 index 00000000..e8aa9c14 --- /dev/null +++ b/resources/icons/podcasting/truefans.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/tsacdop.svg b/resources/icons/podcasting/tsacdop.svg new file mode 100644 index 00000000..680bda13 --- /dev/null +++ b/resources/icons/podcasting/tsacdop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/tunein.svg b/resources/icons/podcasting/tunein.svg new file mode 100755 index 00000000..2e97932b --- /dev/null +++ b/resources/icons/podcasting/tunein.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/podcasting/youtube-music.svg b/resources/icons/podcasting/youtube-music.svg new file mode 100755 index 00000000..55b6d3dd --- /dev/null +++ b/resources/icons/podcasting/youtube-music.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/_index.php b/resources/icons/social/_index.php new file mode 100644 index 00000000..72ef25ca --- /dev/null +++ b/resources/icons/social/_index.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/resources/icons/social/castopod.svg b/resources/icons/social/castopod.svg new file mode 100755 index 00000000..b0d4374d --- /dev/null +++ b/resources/icons/social/castopod.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/default.svg b/resources/icons/social/default.svg new file mode 100644 index 00000000..80fa3727 --- /dev/null +++ b/resources/icons/social/default.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/discord.svg b/resources/icons/social/discord.svg new file mode 100644 index 00000000..b58f33e9 --- /dev/null +++ b/resources/icons/social/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/discourse.svg b/resources/icons/social/discourse.svg new file mode 100644 index 00000000..b8f621c7 --- /dev/null +++ b/resources/icons/social/discourse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/facebook.svg b/resources/icons/social/facebook.svg new file mode 100755 index 00000000..5246848b --- /dev/null +++ b/resources/icons/social/facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/funkwhale.svg b/resources/icons/social/funkwhale.svg new file mode 100755 index 00000000..8ec1da29 --- /dev/null +++ b/resources/icons/social/funkwhale.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/instagram.svg b/resources/icons/social/instagram.svg new file mode 100755 index 00000000..18f914d8 --- /dev/null +++ b/resources/icons/social/instagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/linkedin.svg b/resources/icons/social/linkedin.svg new file mode 100755 index 00000000..06cc775d --- /dev/null +++ b/resources/icons/social/linkedin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/mastodon.svg b/resources/icons/social/mastodon.svg new file mode 100755 index 00000000..ea82e727 --- /dev/null +++ b/resources/icons/social/mastodon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/matrix.svg b/resources/icons/social/matrix.svg new file mode 100644 index 00000000..ae72a3bd --- /dev/null +++ b/resources/icons/social/matrix.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/misskey.svg b/resources/icons/social/misskey.svg new file mode 100644 index 00000000..bd256f34 --- /dev/null +++ b/resources/icons/social/misskey.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/mobilizon.svg b/resources/icons/social/mobilizon.svg new file mode 100755 index 00000000..55166c3c --- /dev/null +++ b/resources/icons/social/mobilizon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/peertube.svg b/resources/icons/social/peertube.svg new file mode 100755 index 00000000..07e78d42 --- /dev/null +++ b/resources/icons/social/peertube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/pixelfed.svg b/resources/icons/social/pixelfed.svg new file mode 100755 index 00000000..70d7f222 --- /dev/null +++ b/resources/icons/social/pixelfed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/pleroma.svg b/resources/icons/social/pleroma.svg new file mode 100644 index 00000000..06795c62 --- /dev/null +++ b/resources/icons/social/pleroma.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/plume.svg b/resources/icons/social/plume.svg new file mode 100755 index 00000000..17a3e787 --- /dev/null +++ b/resources/icons/social/plume.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/reddit.svg b/resources/icons/social/reddit.svg new file mode 100755 index 00000000..c6f879fe --- /dev/null +++ b/resources/icons/social/reddit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/slack.svg b/resources/icons/social/slack.svg new file mode 100755 index 00000000..4bddffc1 --- /dev/null +++ b/resources/icons/social/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/telegram.svg b/resources/icons/social/telegram.svg new file mode 100644 index 00000000..8c1bb674 --- /dev/null +++ b/resources/icons/social/telegram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/threads.svg b/resources/icons/social/threads.svg new file mode 100644 index 00000000..691d7276 --- /dev/null +++ b/resources/icons/social/threads.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/tiktok.svg b/resources/icons/social/tiktok.svg new file mode 100755 index 00000000..c68b6645 --- /dev/null +++ b/resources/icons/social/tiktok.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/twitch.svg b/resources/icons/social/twitch.svg new file mode 100755 index 00000000..14747c46 --- /dev/null +++ b/resources/icons/social/twitch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/twitter.svg b/resources/icons/social/twitter.svg new file mode 100755 index 00000000..1d17015b --- /dev/null +++ b/resources/icons/social/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/writefreely.svg b/resources/icons/social/writefreely.svg new file mode 100755 index 00000000..05965a88 --- /dev/null +++ b/resources/icons/social/writefreely.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/x.svg b/resources/icons/social/x.svg new file mode 100755 index 00000000..9da09775 --- /dev/null +++ b/resources/icons/social/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/social/youtube.svg b/resources/icons/social/youtube.svg new file mode 100755 index 00000000..279e6b32 --- /dev/null +++ b/resources/icons/social/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Resources/js/modules/Charts.ts b/resources/js/_modules/Charts.ts similarity index 87% rename from app/Resources/js/modules/Charts.ts rename to resources/js/_modules/Charts.ts index 886fa620..c949599b 100644 --- a/app/Resources/js/modules/Charts.ts +++ b/resources/js/_modules/Charts.ts @@ -5,9 +5,12 @@ import * as am4maps from "@amcharts/amcharts4/maps"; import * as am4plugins_sliceGrouper from "@amcharts/amcharts4/plugins/sliceGrouper"; import am4themes_material from "@amcharts/amcharts4/themes/material"; -const drawPieChart = (chartDivId: string, dataUrl: string | null): void => { +const drawPieChart = ( + chartDiv: HTMLDivElement, + dataUrl: string | null +): void => { // Create chart instance - const chart = am4core.create(chartDivId, am4charts.PieChart); + const chart = am4core.create(chartDiv, am4charts.PieChart); am4core.percent(100); chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.menu.align = "left"; @@ -43,9 +46,12 @@ const drawPieChart = (chartDivId: string, dataUrl: string | null): void => { chart.legend.scrollable = true; }; -const drawXYChart = (chartDivId: string, dataUrl: string | null): void => { +const drawXYChart = ( + chartDiv: HTMLDivElement, + dataUrl: string | null +): void => { // Create chart instance - const chart = am4core.create(chartDivId, am4charts.XYChart); + const chart = am4core.create(chartDiv, am4charts.XYChart); am4core.percent(100); chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.menu.align = "right"; @@ -88,9 +94,12 @@ const drawXYChart = (chartDivId: string, dataUrl: string | null): void => { chart.scrollbarX = new am4core.Scrollbar(); }; -const drawBarChart = (chartDivId: string, dataUrl: string | null): void => { +const drawBarChart = ( + chartDiv: HTMLDivElement, + dataUrl: string | null +): void => { // Create chart instance - const chart = am4core.create(chartDivId, am4charts.XYChart); + const chart = am4core.create(chartDiv, am4charts.XYChart); am4core.percent(100); chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.menu.align = "right"; @@ -121,11 +130,11 @@ const drawBarChart = (chartDivId: string, dataUrl: string | null): void => { }; const drawXYDurationChart = ( - chartDivId: string, + chartDiv: HTMLDivElement, dataUrl: string | null ): void => { // Create chart instance - const chart = am4core.create(chartDivId, am4charts.XYChart); + const chart = am4core.create(chartDiv, am4charts.XYChart); am4core.percent(100); chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.menu.align = "right"; @@ -140,7 +149,7 @@ const drawXYDurationChart = ( const yAxis = chart.yAxes.push(new am4charts.DurationAxis()); yAxis.baseUnit = "second"; - chart.durationFormatter.durationFormat = "hh'h,' mm'mn'"; + chart.durationFormatter.durationFormat = "hh'h'mm"; // Add data chart.dataSource.url = dataUrl || ""; @@ -171,9 +180,12 @@ const drawXYDurationChart = ( chart.scrollbarX = new am4core.Scrollbar(); }; -const drawMapChart = (chartDivId: string, dataUrl: string | null): void => { +const drawMapChart = ( + chartDiv: HTMLDivElement, + dataUrl: string | null +): void => { // Create map instance - const chart = am4core.create(chartDivId, am4maps.MapChart); + const chart = am4core.create(chartDiv, am4maps.MapChart); am4core.percent(100); chart.exporting.menu = new am4core.ExportMenu(); chart.exporting.menu.align = "left"; @@ -238,22 +250,19 @@ const DrawCharts = (): void => { switch (chartType) { case "pie-chart": - drawPieChart(chartDiv.id, chartDiv.getAttribute("data-chart-url")); + drawPieChart(chartDiv, chartDiv.getAttribute("data-chart-url")); break; case "xy-chart": - drawXYChart(chartDiv.id, chartDiv.getAttribute("data-chart-url")); + drawXYChart(chartDiv, chartDiv.getAttribute("data-chart-url")); break; case "bar-chart": - drawBarChart(chartDiv.id, chartDiv.getAttribute("data-chart-url")); + drawBarChart(chartDiv, chartDiv.getAttribute("data-chart-url")); break; case "xy-duration-chart": - drawXYDurationChart( - chartDiv.id, - chartDiv.getAttribute("data-chart-url") - ); + drawXYDurationChart(chartDiv, chartDiv.getAttribute("data-chart-url")); break; case "map-chart": - drawMapChart(chartDiv.id, chartDiv.getAttribute("data-chart-url")); + drawMapChart(chartDiv, chartDiv.getAttribute("data-chart-url")); break; default: console.error("Unknown chart type:" + chartType); diff --git a/app/Resources/js/modules/ClientTimezone.ts b/resources/js/_modules/ClientTimezone.ts similarity index 100% rename from app/Resources/js/modules/ClientTimezone.ts rename to resources/js/_modules/ClientTimezone.ts diff --git a/resources/js/_modules/Clipboard.ts b/resources/js/_modules/Clipboard.ts new file mode 100644 index 00000000..defb176a --- /dev/null +++ b/resources/js/_modules/Clipboard.ts @@ -0,0 +1,22 @@ +const Clipboard = (): void => { + const buttons: NodeListOf | null = + document.querySelectorAll("button[data-type='clipboard-copy']"); + + if (buttons) { + for (let i = 0; i < buttons.length; i++) { + const button: HTMLButtonElement = buttons[i]; + const element: HTMLFormElement | null = document.querySelector( + `[id="${button.dataset.clipboardTarget}"]` + ); + if (element) { + button.addEventListener("click", () => { + element.select(); + element.setSelectionRange(0, element.value.length); + document.execCommand("copy"); + }); + } + } + } +}; + +export default Clipboard; diff --git a/app/Resources/js/modules/DateTimePicker.ts b/resources/js/_modules/DateTimePicker.ts similarity index 79% rename from app/Resources/js/modules/DateTimePicker.ts rename to resources/js/_modules/DateTimePicker.ts index a3ab215a..fb6d8e40 100644 --- a/app/Resources/js/modules/DateTimePicker.ts +++ b/resources/js/_modules/DateTimePicker.ts @@ -1,5 +1,6 @@ import flatpickr from "flatpickr"; import "flatpickr/dist/flatpickr.min.css"; +import "flatpickr/dist/themes/material_green.css"; /* * Detects navigator locale 24h time preference @@ -11,15 +12,13 @@ const isBrowserLocale24h = () => .match(/AM/); const DateTimePicker = (): void => { - const dateTimeContainers: NodeListOf = document.querySelectorAll( - "div[data-picker='datetime']" - ); + const dateTimeContainers: NodeListOf = + document.querySelectorAll("div[data-picker='datetime']"); for (let i = 0; i < dateTimeContainers.length; i++) { const dateTimeContainer = dateTimeContainers[i]; - const dateTimeInput: HTMLInputElement | null = dateTimeContainer.querySelector( - "input[data-input]" - ); + const dateTimeInput: HTMLInputElement | null = + dateTimeContainer.querySelector("input[data-input]"); if (dateTimeInput) { const flatpickrInstance = flatpickr(dateTimeContainer, { diff --git a/resources/js/_modules/Dropdown.ts b/resources/js/_modules/Dropdown.ts new file mode 100644 index 00000000..06cfb9a5 --- /dev/null +++ b/resources/js/_modules/Dropdown.ts @@ -0,0 +1,87 @@ +import { + computePosition, + flip, + offset, + Placement, + shift, +} from "@floating-ui/dom"; + +const Dropdown = (): void => { + const dropdownButtons: NodeListOf = + document.querySelectorAll("[data-dropdown='button']"); + + for (let i = 0; i < dropdownButtons.length; i++) { + const button = dropdownButtons[i]; + + if (button.dataset.dropdownTarget) { + const menu: HTMLElement | null = document.getElementById( + button.dataset?.dropdownTarget + ); + + if (menu) { + // place the menu at then end of the body to prevent any overflow cuts + document.body.appendChild(menu); + + const update = () => { + const offsetX = menu.dataset.dropdownOffsetX + ? parseInt(menu.dataset.dropdownOffsetX) + : 0; + const offsetY = menu.dataset.dropdownOffsetY + ? parseInt(menu.dataset.dropdownOffsetY) + : 0; + computePosition(button, menu, { + placement: menu.dataset.dropdownPlacement as Placement, + middleware: [ + offset({ mainAxis: offsetY, crossAxis: offsetX }), + flip(), + shift(), + ], + }).then(({ x, y }) => { + Object.assign(menu.style, { + left: `${x}px`, + top: `${y}px`, + }); + }); + }; + + const showMenu = () => { + menu.setAttribute("data-show", ""); + button.setAttribute("aria-expanded", "true"); + update(); + }; + + const hideMenu = () => { + menu.removeAttribute("data-show"); + button.setAttribute("aria-expanded", "false"); + }; + + const dropdownToggle = () => { + const isExpanded = menu.hasAttribute("data-show"); + + if (isExpanded) { + hideMenu(); + } else { + showMenu(); + } + }; + + // Toggle dropdown menu on button click event + button.addEventListener("click", dropdownToggle); + + // Toggle off when clicking outside of dropdown + document.addEventListener("click", function (event) { + const isExpanded = menu.hasAttribute("data-show"); + const isClickOutside = + !menu.contains(event.target as Node) && + !button.contains(event.target as Node); + + if (isExpanded && isClickOutside) { + dropdownToggle(); + } + }); + } + } + } +}; + +export default Dropdown; diff --git a/app/Resources/js/modules/EpisodesMap.ts b/resources/js/_modules/EpisodesMap.ts similarity index 83% rename from app/Resources/js/modules/EpisodesMap.ts rename to resources/js/_modules/EpisodesMap.ts index 41b794c5..bc0b2ed5 100644 --- a/app/Resources/js/modules/EpisodesMap.ts +++ b/resources/js/_modules/EpisodesMap.ts @@ -11,14 +11,11 @@ import { MarkerClusterGroup } from "leaflet.markercluster"; import "leaflet.markercluster/dist/MarkerCluster.css"; import "leaflet.markercluster/dist/MarkerCluster.Default.css"; import "leaflet/dist/leaflet.css"; -import markerIconRetina from "../../images/marker/marker-icon-2x.png"; -import markerIcon from "../../images/marker/marker-icon.png"; -import markerShadow from "../../images/marker/marker-shadow.png"; Marker.prototype.options.icon = icon({ - iconRetinaUrl: markerIconRetina, - iconUrl: markerIcon, - shadowUrl: markerShadow, + iconRetinaUrl: "/assets/images/marker/marker-icon-2x.png", + iconUrl: "/assets/images/marker/marker-icon.png", + shadowUrl: "/assets/images/marker/marker-shadow.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], @@ -46,13 +43,13 @@ const drawEpisodesMap = async (mapDivId: string, dataUrl: string) => { data[i].latitude, data[i].longitude, ]).bindPopup( - '
    ' +
           data[i].episode_title +
-          '

    ' + + '" class="hover:underline font-semibold !text-accent-base">' + data[i].episode_title + '

    { + const fieldArrays: NodeListOf = + document.querySelectorAll("[data-field-array]"); + + for (let i = 0; i < fieldArrays.length; i++) { + const fieldArray = fieldArrays[i]; + const fieldArrayContainer = fieldArray.querySelector( + "[data-field-array-container]" + ); + const items: NodeListOf = fieldArray.querySelectorAll( + "[data-field-array-item]" + ); + const addButton = fieldArray.querySelector( + "button[data-field-array-add]" + ) as HTMLButtonElement; + + const deleteButtons: NodeListOf = + fieldArray.querySelectorAll("[data-field-array-delete]"); + + deleteButtons.forEach((deleteBtn) => { + deleteBtn.addEventListener("click", (e) => { + e.preventDefault(); + deleteBtn.blur(); + fieldArrayContainer + ?.querySelector( + `[data-field-array-item="${deleteBtn.dataset.fieldArrayDelete}"]` + ) + ?.remove(); + }); + }); + + // create base element to clone + const baseItem = items[0].cloneNode(true) as HTMLElement; + + const elements: NodeListOf = baseItem.querySelectorAll( + "input, select, textarea" + ); + + elements.forEach((element) => { + element.value = ""; + }); + + if (fieldArrayContainer && addButton) { + addButton.addEventListener("click", (event) => { + event.preventDefault(); + + const newItem = baseItem.cloneNode(true) as HTMLElement; + + const deleteBtn: HTMLButtonElement | null = newItem.querySelector( + "button[data-field-array-delete]" + ); + + if (deleteBtn) { + deleteBtn.addEventListener("click", () => { + deleteBtn.blur(); + newItem.remove(); + }); + + fieldArrayContainer.appendChild(newItem); + newItem.scrollIntoView({ + behavior: "auto", + block: "center", + inline: "center", + }); + + // reload tooltip module for showing remove button label + Tooltip(); + + // focus to first form element if mouse click + if (event.screenX !== 0 && event.screenY !== 0) { + const elements: NodeListOf = + newItem.querySelectorAll("input, select, textarea"); + + if (elements.length > 0) { + elements[0].focus(); + } + } + } + }); + + const updateIndexes = () => { + // get last child item to set item count + const items: NodeListOf = + fieldArrayContainer.querySelectorAll("[data-field-array-item]"); + + let itemIndex = 0; + items.forEach((item) => { + const itemNumber: HTMLElement | null = item.querySelector( + "[data-field-array-number]" + ); + + if (itemNumber) { + itemNumber.innerHTML = "#"; + const indexNum = itemIndex + 1; + if (item.dataset.fieldArrayItem !== itemIndex.toString()) { + item.classList.add("motion-safe:animate-single-pulse"); + setTimeout(() => { + item.classList.remove("motion-safe:animate-single-pulse"); + itemNumber.innerHTML = indexNum.toString(); + }, 300); + } else { + itemNumber.innerHTML = indexNum.toString(); + } + } + + item.dataset.fieldArrayItem = itemIndex.toString(); + const deleteBtn = item.querySelector( + "button[data-field-array-delete]" + ) as HTMLButtonElement | null; + + if (deleteBtn) { + deleteBtn.dataset.fieldArrayDelete = itemIndex.toString(); + } + + const itemElements: NodeListOf = + item.querySelectorAll("input, select, textarea"); + + itemElements.forEach((element) => { + const label: HTMLLabelElement | null = item.querySelector( + `label[for="${element.id}"]` + ); + + const elementID = element.name.replace( + /(.*\[)\d+?(\].*)/g, + `$1${itemIndex}$2` + ); + + if (label) { + label.htmlFor = elementID; + } + + element.id = elementID; + element.name = elementID; + }); + + itemIndex++; + }); + }; + + // add mutation observer to run index updates when field array + // items are added or removed + const callback = function (mutationList: MutationRecord[]) { + for (const mutation of mutationList) { + if (mutation.type === "childList") { + updateIndexes(); + } + } + }; + + const observer = new MutationObserver(callback); + + observer.observe(fieldArrayContainer, { childList: true }); + } + } +}; + +export default FieldArray; diff --git a/resources/js/_modules/HotKeys.ts b/resources/js/_modules/HotKeys.ts new file mode 100644 index 00000000..c729bd83 --- /dev/null +++ b/resources/js/_modules/HotKeys.ts @@ -0,0 +1,14 @@ +import { install } from "@github/hotkey"; + +const HotKeys = (): void => { + const hotkeys: NodeListOf = + document.querySelectorAll("[data-hotkey]"); + + // Install all the hotkeys on the page + for (let i = 0; i < hotkeys.length; i++) { + const hotkey = hotkeys[i]; + install(hotkey); + } +}; + +export default HotKeys; diff --git a/resources/js/_modules/Modal.ts b/resources/js/_modules/Modal.ts new file mode 100644 index 00000000..5d404c10 --- /dev/null +++ b/resources/js/_modules/Modal.ts @@ -0,0 +1,32 @@ +const Modal = (): void => { + const modalTriggerElements: NodeListOf = + document.querySelectorAll("[data-modal-target]"); + + for (let i = 0; i < modalTriggerElements.length; i++) { + const modalTrigger = modalTriggerElements[i]; + + if (modalTrigger.dataset.modalTarget) { + const modal: HTMLElement | null = document.getElementById( + modalTrigger.dataset.modalTarget + ); + + if (modal) { + modalTrigger.addEventListener("click", () => { + modal.classList.toggle("hidden"); + }); + + const closeButtonsElements: NodeListOf = + modal.querySelectorAll("[data-modal-button]"); + + for (let j = 0; j < closeButtonsElements.length; j++) { + const closeButton = closeButtonsElements[j]; + closeButton.addEventListener("click", () => { + modal.classList.toggle("hidden"); + }); + } + } + } + } +}; + +export default Modal; diff --git a/app/Resources/js/modules/PublishMessageWarning.ts b/resources/js/_modules/PublishMessageWarning.ts similarity index 84% rename from app/Resources/js/modules/PublishMessageWarning.ts rename to resources/js/_modules/PublishMessageWarning.ts index fbde59f4..161beaf9 100644 --- a/app/Resources/js/modules/PublishMessageWarning.ts +++ b/resources/js/_modules/PublishMessageWarning.ts @@ -4,15 +4,13 @@ const PublishMessageWarning = (): void => { ); if (publishForm) { - const messageTextArea: HTMLTextAreaElement | null = publishForm.querySelector( - "[name='message']" - ); + const messageTextArea: HTMLTextAreaElement | null = + publishForm.querySelector("[name='message']"); const submitButton: HTMLButtonElement | null = publishForm.querySelector( "button[type='submit']" ); - const publishMessageWarning: HTMLDivElement | null = publishForm.querySelector( - "[id='publish-warning']" - ); + const publishMessageWarning: HTMLDivElement | null = + publishForm.querySelector("[id='publish-warning']"); if ( messageTextArea && diff --git a/resources/js/_modules/Select.ts b/resources/js/_modules/Select.ts new file mode 100644 index 00000000..840dfed8 --- /dev/null +++ b/resources/js/_modules/Select.ts @@ -0,0 +1,54 @@ +import Choices from "choices.js"; + +const Select = (): void => { + // Pass single element + const selects: NodeListOf = document.querySelectorAll( + "select:not([multiple])" + ); + + for (let i = 0; i < selects.length; i++) { + const select = selects[i]; + + new Choices(select, { + allowHTML: false, + loadingText: select.dataset.loadingText, + itemSelectText: select.dataset.selectText, + maxItemText: select.dataset.maxItemText, + noChoicesText: select.dataset.noChoicesText, + noResultsText: select.dataset.noResultsText, + classNames: { + activeState: "is-active", + addChoice: ["choices__item--selectable", "add-choice"], + button: "choices__button", + containerInner: "choices__inner", + containerOuter: "choices", + description: "choices__description", + disabledState: "is-disabled", + flippedState: "is-flipped", + focusState: "is-focused", + group: "choices__group", + groupHeading: "choices__heading", + highlightedState: "is-highlighted", + input: "choices__input", + inputCloned: "choices__input--cloned", + item: "choices__item", + itemChoice: "choices__item--choice", + itemDisabled: "choices__item--disabled", + itemSelectable: "choices__item--selectable", + list: "choices__list", + listDropdown: "choices__list--dropdown", + listItems: "choices__list--multiple", + listSingle: "choices__list--single", + loadingState: "is-loading", + noChoices: "has-no-choices", + noResults: "has-no-results", + notice: "choices__notice", + openState: "is-open", + placeholder: "choices__placeholder", + selectedState: "is-selected", + }, + }); + } +}; + +export default Select; diff --git a/resources/js/_modules/SelectMulti.ts b/resources/js/_modules/SelectMulti.ts new file mode 100644 index 00000000..064bc78a --- /dev/null +++ b/resources/js/_modules/SelectMulti.ts @@ -0,0 +1,55 @@ +import Choices from "choices.js"; + +const SelectMulti = (): void => { + // Pass single element + const multiSelects: NodeListOf = + document.querySelectorAll("select[multiple]"); + + for (let i = 0; i < multiSelects.length; i++) { + const multiSelect = multiSelects[i]; + + new Choices(multiSelect, { + allowHTML: false, + maxItemCount: parseInt(multiSelect.dataset.maxItemCount || "-1"), + loadingText: multiSelect.dataset.loadingText, + itemSelectText: multiSelect.dataset.selectText, + maxItemText: multiSelect.dataset.maxItemText, + noChoicesText: multiSelect.dataset.noChoicesText, + noResultsText: multiSelect.dataset.noResultsText, + removeItemButton: true, + classNames: { + activeState: "is-active", + addChoice: ["choices__item--selectable", "add-choice"], + button: "choices__button", + containerInner: "choices__inner", + containerOuter: "choices", + description: "choices__description", + disabledState: "is-disabled", + flippedState: "is-flipped", + focusState: "is-focused", + group: "choices__group", + groupHeading: "choices__heading", + highlightedState: "is-highlighted", + input: "choices__input", + inputCloned: "choices__input--cloned", + item: "choices__item", + itemChoice: "choices__item--choice", + itemDisabled: "choices__item--disabled", + itemSelectable: "choices__item--selectable", + list: "choices__list", + listDropdown: "choices__list--dropdown", + listItems: "choices__list--multiple", + listSingle: "choices__list--single", + loadingState: "is-loading", + noChoices: "has-no-choices", + noResults: "has-no-results", + notice: "choices__notice", + openState: "is-open", + placeholder: "choices__placeholder", + selectedState: "is-selected", + }, + }); + } +}; + +export default SelectMulti; diff --git a/resources/js/_modules/SidebarToggler.ts b/resources/js/_modules/SidebarToggler.ts new file mode 100644 index 00000000..f1078857 --- /dev/null +++ b/resources/js/_modules/SidebarToggler.ts @@ -0,0 +1,63 @@ +const SidebarToggler = (): void => { + const sidebar = document.querySelector( + "aside[data-sidebar-toggler='sidebar']" + ) as HTMLElement; + const toggler = document.querySelector( + "button[data-sidebar-toggler='toggler']" + ) as HTMLButtonElement; + const sidebarBackdrop = document.querySelector( + "div[data-sidebar-toggler='backdrop']" + ) as HTMLDivElement; + + if (typeof sidebar.dataset.toggleClass !== "undefined") { + const setAriaExpanded = (isExpanded: "true" | "false") => { + toggler.setAttribute("aria-expanded", isExpanded); + sidebarBackdrop.setAttribute("aria-expanded", isExpanded); + }; + + const hideSidebar = () => { + setAriaExpanded("false"); + sidebar.classList.add(sidebar.dataset.toggleClass as string); + sidebarBackdrop.classList.add("hidden"); + toggler.classList.add(toggler.dataset.toggleClass as string); + }; + + const showSidebar = () => { + setAriaExpanded("true"); + sidebar.classList.remove(sidebar.dataset.toggleClass as string); + sidebarBackdrop.classList.remove("hidden"); + toggler.classList.remove(toggler.dataset.toggleClass as string); + }; + + toggler.addEventListener("click", () => { + if (sidebar.classList.contains(sidebar.dataset.hideClass as string)) { + showSidebar(); + } else { + hideSidebar(); + } + }); + + sidebarBackdrop.addEventListener("click", () => { + if (!sidebar.classList.contains(sidebar.dataset.hideClass as string)) { + hideSidebar(); + } + }); + + const setAriaExpandedOnWindowEvent = () => { + const isExpanded = + !sidebar.classList.contains(sidebar.dataset.hideClass as string) || + window.innerWidth >= 768; + const ariaExpanded = toggler.getAttribute("aria-expanded"); + if (isExpanded && (!ariaExpanded || ariaExpanded === "false")) { + setAriaExpanded("true"); + } else if (!isExpanded && (!ariaExpanded || ariaExpanded === "true")) { + setAriaExpanded("false"); + } + }; + + window.addEventListener("load", setAriaExpandedOnWindowEvent); + window.addEventListener("resize", setAriaExpandedOnWindowEvent); + } +}; + +export default SidebarToggler; diff --git a/app/Resources/js/modules/Slugify.ts b/resources/js/_modules/Slugify.ts similarity index 96% rename from app/Resources/js/modules/Slugify.ts rename to resources/js/_modules/Slugify.ts index 0a84ac3f..41251722 100644 --- a/app/Resources/js/modules/Slugify.ts +++ b/resources/js/_modules/Slugify.ts @@ -29,6 +29,7 @@ const Slugify = (): void => { if (title && slug) { title.addEventListener("input", () => { slug.value = slugify(title.value); + slug.dispatchEvent(new Event("change")); }); } }; diff --git a/resources/js/_modules/ThemePicker.ts b/resources/js/_modules/ThemePicker.ts new file mode 100644 index 00000000..850fb0a6 --- /dev/null +++ b/resources/js/_modules/ThemePicker.ts @@ -0,0 +1,26 @@ +const ThemePicker = (): void => { + const buttons: NodeListOf | null = + document.querySelectorAll("button[data-type='theme-picker']"); + const iframe: HTMLIFrameElement | null = + document.querySelector(`iframe[id="embed"]`); + const iframeTextArea: HTMLFormElement | null = + document.querySelector(`[id="iframe"]`); + const urlTextArea: HTMLFormElement | null = + document.querySelector(`[id="url"]`); + + if (buttons && iframe && iframeTextArea && urlTextArea) { + for (let i = 0; i < buttons.length; i++) { + const button: HTMLButtonElement = buttons[i]; + const url: string | undefined = button.dataset.url; + if (url) { + button.addEventListener("click", () => { + iframeTextArea.value = ``; + urlTextArea.value = url; + iframe.src = url; + }); + } + } + } +}; + +export default ThemePicker; diff --git a/app/Resources/js/modules/Time.ts b/resources/js/_modules/Time.ts similarity index 86% rename from app/Resources/js/modules/Time.ts rename to resources/js/_modules/Time.ts index 17dd8cf2..f620081b 100644 --- a/app/Resources/js/modules/Time.ts +++ b/resources/js/_modules/Time.ts @@ -1,7 +1,6 @@ const Time = (): void => { - const timeElements: NodeListOf = document.querySelectorAll( - "time" - ); + const timeElements: NodeListOf = + document.querySelectorAll("time"); for (let i = 0; i < timeElements.length; i++) { const timeElement = timeElements[i]; diff --git a/app/Resources/js/modules/Toggler.ts b/resources/js/_modules/Toggler.ts similarity index 88% rename from app/Resources/js/modules/Toggler.ts rename to resources/js/_modules/Toggler.ts index c726ac1e..4b33a0ba 100644 --- a/app/Resources/js/modules/Toggler.ts +++ b/resources/js/_modules/Toggler.ts @@ -1,7 +1,6 @@ const Toggler = (): void => { - const togglerElements: NodeListOf = document.querySelectorAll( - "[data-toggle]" - ); + const togglerElements: NodeListOf = + document.querySelectorAll("[data-toggle]"); for (let i = 0; i < togglerElements.length; i++) { const toggler = togglerElements[i]; diff --git a/resources/js/_modules/Tooltip.ts b/resources/js/_modules/Tooltip.ts new file mode 100644 index 00000000..5ea75754 --- /dev/null +++ b/resources/js/_modules/Tooltip.ts @@ -0,0 +1,98 @@ +import { + arrow, + computePosition, + Coords, + flip, + offset, + Placement, + shift, +} from "@floating-ui/dom"; + +const Tooltip = (): void => { + const tooltipContainers: NodeListOf = + document.querySelectorAll("[data-tooltip]"); + + for (let i = 0; i < tooltipContainers.length; i++) { + const tooltipReference = tooltipContainers[i]; + const tooltipContent = tooltipReference.title; + + const tooltip = document.createElement("div"); + tooltip.setAttribute("id", "tooltip" + i); + tooltip.setAttribute( + "class", + "absolute px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50" + ); + tooltip.innerHTML = tooltipContent; + const arrowElement = document.createElement("div"); + arrowElement.setAttribute( + "class", + "absolute bg-gray-900 w-2 h-2 rotate-45" + ); + arrowElement.setAttribute("id", "arrow" + i); + tooltip.appendChild(arrowElement); + + const update = () => { + computePosition(tooltipReference, tooltip, { + placement: tooltipReference.dataset.tooltip as Placement, + middleware: [ + flip(), + shift(), + offset(8), + arrow({ element: arrowElement }), + ], + }).then(({ x, y, placement, middlewareData }) => { + Object.assign(tooltip.style, { + left: `${x}px`, + top: `${y}px`, + }); + + // Accessing the data + const { x: arrowX, y: arrowY } = middlewareData.arrow as Coords; + + const staticSide = { + top: "bottom", + right: "left", + bottom: "top", + left: "right", + }[placement.split("-")[0]]; + + Object.assign(arrowElement.style, { + left: arrowX != null ? `${arrowX}px` : "", + top: arrowY != null ? `${arrowY}px` : "", + right: "", + bottom: "", + [staticSide as string]: "-4px", + }); + }); + }; + + const showTooltip = () => { + tooltipReference.removeAttribute("title"); + tooltipReference.setAttribute("aria-describedby", "tooltip" + i); + document.body.appendChild(tooltip); + update(); + }; + + const hideTooltip = () => { + const element = document.getElementById("tooltip" + i); + tooltipReference.removeAttribute("aria-describedby"); + tooltipReference.setAttribute("title", tooltipContent); + if (element) { + document.body.removeChild(element); + } + }; + + const showEvents = ["mouseenter", "focus"]; + const hideEvents = ["mouseleave", "blur"]; + + showEvents.forEach((event) => { + tooltipReference.addEventListener(event, showTooltip); + }); + + hideEvents.forEach((event) => { + tooltipReference.addEventListener(event, hideTooltip); + }); + } +}; + +export default Tooltip; diff --git a/resources/js/_modules/ValidateFileSize.ts b/resources/js/_modules/ValidateFileSize.ts new file mode 100644 index 00000000..b843d5ea --- /dev/null +++ b/resources/js/_modules/ValidateFileSize.ts @@ -0,0 +1,22 @@ +const ValidateFileSize = (): void => { + const fileInputContainers: NodeListOf = + document.querySelectorAll("[data-max-size]"); + + for (let i = 0; i < fileInputContainers.length; i++) { + const fileInput = fileInputContainers[i] as HTMLInputElement; + + fileInput.addEventListener("change", () => { + if (fileInput.files) { + const fileSize = fileInput.files[0].size; + + if (fileSize > parseFloat(fileInput.dataset.maxSize ?? "0")) { + alert(fileInput.dataset.maxSizeError); + // remove the selected file by resetting input to prevent from uploading it. + fileInput.value = ""; + } + } + }); + } +}; + +export default ValidateFileSize; diff --git a/resources/js/_modules/VideoClipBuilder.ts b/resources/js/_modules/VideoClipBuilder.ts new file mode 100644 index 00000000..b3a0865c --- /dev/null +++ b/resources/js/_modules/VideoClipBuilder.ts @@ -0,0 +1,71 @@ +const VideoClipBuilder = (): void => { + const form = document.querySelector("form[id=new-video-clip-form]"); + + if (form) { + const videoClipPreviewer = form?.querySelector("video-clip-previewer"); + + if (videoClipPreviewer) { + const themeOptions: NodeListOf = form.querySelectorAll( + 'input[name="theme"]' + ) as NodeListOf; + const formatOptions: NodeListOf = form.querySelectorAll( + 'input[name="format"]' + ) as NodeListOf; + + const titleInput = form.querySelector( + 'input[name="title"]' + ) as HTMLInputElement; + if (titleInput) { + videoClipPreviewer.setAttribute("title", titleInput.value || ""); + titleInput.addEventListener("input", () => { + videoClipPreviewer.setAttribute("title", titleInput.value || ""); + }); + } + + let format = ( + form.querySelector('input[name="format"]:checked') as HTMLInputElement + )?.value; + videoClipPreviewer.setAttribute("format", format); + const watchFormatChange = (event: Event) => { + format = (event.target as HTMLInputElement).value; + videoClipPreviewer.setAttribute("format", format); + }; + for (let i = 0; i < formatOptions.length; i++) { + formatOptions[i].addEventListener("change", watchFormatChange); + } + + let theme = form + .querySelector('input[name="theme"]:checked') + ?.parentElement?.style.getPropertyValue("--color-background-preview"); + videoClipPreviewer.setAttribute("theme", theme || ""); + + const watchThemeChange = (event: Event) => { + theme = + ( + event.target as HTMLInputElement + ).parentElement?.style.getPropertyValue( + "--color-background-preview" + ) ?? theme; + videoClipPreviewer.setAttribute("theme", theme || ""); + }; + for (let i = 0; i < themeOptions.length; i++) { + themeOptions[i].addEventListener("change", watchThemeChange); + } + + const durationInput = form.querySelector( + 'input[name="duration"]' + ) as HTMLInputElement; + if (durationInput) { + videoClipPreviewer.setAttribute("duration", durationInput.value || "0"); + durationInput.addEventListener("change", () => { + videoClipPreviewer.setAttribute( + "duration", + durationInput.value || "0" + ); + }); + } + } + } +}; + +export default VideoClipBuilder; diff --git a/resources/js/_modules/audio-clipper.ts b/resources/js/_modules/audio-clipper.ts new file mode 100644 index 00000000..a5521273 --- /dev/null +++ b/resources/js/_modules/audio-clipper.ts @@ -0,0 +1,961 @@ +import { css, html, LitElement, TemplateResult } from "lit"; +import { + customElement, + property, + query, + queryAll, + queryAssignedElements, + state, +} from "lit/decorators.js"; +import WaveSurfer, { WaveSurferOptions } from "wavesurfer.js"; + +enum ActionType { + StretchLeft, + StretchRight, + Seek, +} + +interface Action { + type: ActionType; + payload?: { + offset: number; + }; +} + +interface EventElement { + events: string[]; + onEvent: EventListener; +} + +@customElement("audio-clipper") +export class AudioClipper extends LitElement { + @queryAssignedElements({ slot: "audio", flatten: true }) + _audio!: Array; + + @queryAssignedElements({ slot: "start_time", flatten: true }) + _startTimeInput!: Array; + + @queryAssignedElements({ slot: "duration", flatten: true }) + _durationInput!: Array; + + @query(".slider") + _sliderNode!: HTMLDivElement; + + @query(".slider__segment--wrapper") + _segmentNode!: HTMLDivElement; + + @query(".slider__segment-content") + _segmentContentNode!: HTMLDivElement; + + @query(".slider__segment-progress-handle--main") + _progressNode!: HTMLDivElement; + + @query(".slider__segment-progress-handle--ghost") + _progressGhostNode!: HTMLDivElement; + + @query(".slider__seeking-placeholder") + _seekingNode!: HTMLDivElement; + + @query("#waveform") + _waveformNode!: HTMLDivElement; + + @query(".buffering-bar") + _bufferingBarNode!: HTMLCanvasElement; + + @queryAll(".slider__segment-handle") + _segmentHandleNodes!: NodeListOf; + + @property({ type: Number, attribute: "audio-duration" }) + audioDuration = 0; + + @property({ type: Number, attribute: "start-time" }) + initStartTime = 0; + + @property({ type: Number, attribute: "duration" }) + initDuration = 10; + + @property({ type: Number, attribute: "min-duration" }) + minDuration = 5; + + @property({ type: Number, attribute: "volume" }) + initVolume = 0.5; + + @property({ type: Number, attribute: "height" }) + height = 100; + + @property({ attribute: "trim-start-label" }) + trimStartLabel = "Trim start"; + + @property({ attribute: "trim-end-label" }) + trimEndLabel = "Trim end"; + + @state() + _canInteract = false; + + @state() + _isPlaying = false; + + @state() + _clip = { + startTime: 0, + endTime: 0, + }; + + @state() + _action: Action | null = null; + + @state() + _sliderWidth = 0; + + @state() + _currentTime = 0; + + @state() + _volume = 0.5; + + @state() + _seekingTime: number | null = null; + + @state() + _wavesurfer!: WaveSurfer; + + @state() + _isBuffering = false; + + _windowEvents: EventElement[] = [ + { + events: ["load"], + onEvent: () => { + this._canInteract = true; + this._sliderWidth = this._sliderNode.clientWidth; + this.setSegmentPosition(); + }, + }, + { + events: ["resize"], + onEvent: () => { + this._sliderWidth = this._sliderNode.clientWidth; + this.setSegmentPosition(); + }, + }, + ]; + + _documentEvents: EventElement[] = [ + { + events: ["mouseup"], + onEvent: () => { + if (this._action !== null) { + document.body.style.cursor = ""; + if ( + this._action.type === ActionType.Seek && + this._seekingTime !== null + ) { + this._audio[0].currentTime = this._seekingTime; + this._seekingTime = null; + } + this._action = null; + } + }, + }, + { + events: ["mousemove"], + onEvent: (event: Event) => { + this.updatePosition(event as MouseEvent); + }, + }, + ]; + + _audioEvents: EventElement[] = [ + { + events: ["loadedmetadata"], + onEvent: () => { + this.audioDuration = this._audio[0].duration; + }, + }, + { + events: ["waiting"], + onEvent: () => { + this._isBuffering = true; + }, + }, + { + events: ["play"], + onEvent: () => { + this._isPlaying = true; + }, + }, + { + events: ["pause"], + onEvent: () => { + this._isPlaying = false; + }, + }, + { + events: ["progress"], + onEvent: () => { + const context = this._bufferingBarNode.getContext("2d"); + + if (context) { + context.fillStyle = "lightgray"; + context.fillRect( + 0, + 0, + this._bufferingBarNode.width, + this._bufferingBarNode.height + ); + context.fillStyle = "#04AC64"; + + const inc = this._bufferingBarNode.width / this.audioDuration; + + for (let i = 0; i < this._audio[0].buffered.length; i++) { + const startX = this._audio[0].buffered.start(i) * inc; + const endX = this._audio[0].buffered.end(i) * inc; + const width = endX - startX; + + context.fillRect(startX, 0, width, this._bufferingBarNode.height); + context.rect(startX, 0, width, this._bufferingBarNode.height); + } + } + }, + }, + { + events: ["timeupdate"], + onEvent: () => { + this._currentTime = this._audio[0].currentTime; + if (this._currentTime > this._clip.endTime) { + this.pause(); + this._audio[0].currentTime = this._clip.endTime; + } else if (this._currentTime < this._clip.startTime) { + this._audio[0].currentTime = this._clip.startTime; + } else { + this._isBuffering = false; + this.setCurrentTime(this._currentTime); + } + }, + }, + ]; + + _segmentHandleEvents: EventElement[] = [ + { + events: ["mouseenter", "focus"], + onEvent: (event: Event) => { + const timeInfoElement = ( + event.target as HTMLButtonElement + ).querySelector("span"); + if (timeInfoElement) { + timeInfoElement.style.opacity = "1"; + } + }, + }, + { + events: ["mouseleave", "blur"], + onEvent: (event: Event) => { + const timeInfoElement = ( + event.target as HTMLButtonElement + ).querySelector("span"); + if (timeInfoElement) { + timeInfoElement.style.opacity = "0"; + } + }, + }, + ]; + + _sliderSegmentEvents: EventElement[] = [ + { + events: ["hover"], + onEvent: (event: Event) => { + const ghostHandle = (event.target as HTMLDivElement).querySelector( + ".segment" + ) as HTMLDivElement; + if (ghostHandle) { + ghostHandle.style.opacity = "1"; + ghostHandle.style.transform = "translateX(50)"; + } + }, + }, + ]; + + connectedCallback(): void { + super.connectedCallback(); + + this._clip = { + startTime: this.initStartTime, + endTime: this.initStartTime + this.initDuration, + }; + this._volume = this.initVolume; + } + + protected firstUpdated(): void { + this._sliderWidth = this._sliderNode.clientWidth; + this.setSegmentPosition(); + + this._audio[0].volume = this._volume; + this._startTimeInput[0].hidden = true; + this._durationInput[0].hidden = true; + + this._wavesurfer = WaveSurfer.create({ + container: this._waveformNode, + height: this.height, + interact: false, + barWidth: 2, + barHeight: 1, + responsive: true, + waveColor: "hsl(0 5% 85%)", + cursorColor: "transparent", + } as WaveSurferOptions); + this._wavesurfer.load(this._audio[0].src); + + this.addEventListeners(); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this.removeEventListeners(); + } + + addEventListeners(): void { + for (const event of this._windowEvents) { + event.events.forEach((name) => { + window.addEventListener(name, event.onEvent); + }); + } + + for (const event of this._documentEvents) { + event.events.forEach((name) => { + document.addEventListener(name, event.onEvent); + }); + } + + for (const event of this._audioEvents) { + event.events.forEach((name) => { + this._audio[0].addEventListener(name, event.onEvent); + }); + } + + for (const event of this._segmentHandleEvents) { + event.events.forEach((name) => { + for (let i = 0; i < this._segmentHandleNodes.length; i++) { + this._segmentHandleNodes[i].addEventListener(name, event.onEvent); + } + }); + } + } + + removeEventListeners(): void { + for (const event of this._windowEvents) { + event.events.forEach((name) => { + window.removeEventListener(name, event.onEvent); + }); + } + + for (const event of this._documentEvents) { + event.events.forEach((name) => { + document.removeEventListener(name, event.onEvent); + }); + } + + for (const event of this._audioEvents) { + event.events.forEach((name) => { + this._audio[0].removeEventListener(name, event.onEvent); + }); + } + + for (const event of this._segmentHandleEvents) { + event.events.forEach((name) => { + for (let i = 0; i < this._segmentHandleNodes.length; i++) { + this._segmentHandleNodes[i].addEventListener(name, event.onEvent); + } + }); + } + } + + setSegmentPosition(): void { + const startTimePosition = this.getPositionFromSeconds(this._clip.startTime); + const endTimePosition = this.getPositionFromSeconds(this._clip.endTime); + + this._segmentNode.style.transform = `translateX(${startTimePosition}px)`; + this._segmentContentNode.style.width = `${ + endTimePosition - startTimePosition + }px`; + } + + private getPositionFromSeconds(seconds: number) { + return (seconds * this._sliderWidth) / this.audioDuration; + } + + private getSecondsFromPosition(position: number) { + return (this.audioDuration * position) / this._sliderWidth; + } + + protected updated( + _changedProperties: Map + ): void { + if (_changedProperties.has("_clip")) { + this.pause(); + this.setSegmentPosition(); + + this._startTimeInput[0].value = this._clip.startTime.toString(); + this._durationInput[0].value = ( + this._clip.endTime - this._clip.startTime + ).toFixed(3); + this._durationInput[0].dispatchEvent(new Event("change")); + this._audio[0].currentTime = this._clip.startTime; + } + if (_changedProperties.has("_seekingTime")) { + if (this._seekingTime) { + this._audio[0].currentTime = this._seekingTime; + } + } + } + + play(): void { + this._audio[0].play(); + } + + pause(): void { + this._audio[0].pause(); + } + + private updatePosition(event: MouseEvent): void { + if (this._action === null) { + return; + } + + const cursorPosition = + event.clientX + + (this._action.payload?.offset || 0) - + (this._sliderNode.getBoundingClientRect().left + + document.documentElement.scrollLeft); + + const seconds = this.getSecondsFromPosition(cursorPosition); + + switch (this._action.type) { + case ActionType.StretchLeft: { + let startTime = 0; + if (seconds > 0) { + if (seconds > this._clip.endTime - this.minDuration) { + startTime = this._clip.endTime - this.minDuration; + } else { + startTime = seconds; + } + } + this._clip = { + startTime: parseFloat(startTime.toFixed(3)), + endTime: this._clip.endTime, + }; + break; + } + case ActionType.StretchRight: { + let endTime; + if (seconds < this.audioDuration) { + if (seconds < this._clip.startTime + this.minDuration) { + endTime = this._clip.startTime + this.minDuration; + } else { + endTime = seconds; + } + } else { + endTime = this.audioDuration; + } + + this._clip = { + startTime: this._clip.startTime, + endTime: parseFloat(endTime.toFixed(3)), + }; + break; + } + case ActionType.Seek: { + if (seconds < this._clip.startTime) { + this._seekingTime = this._clip.startTime; + } else if (seconds > this._clip.endTime) { + this._seekingTime = this._clip.endTime; + } else { + this._seekingTime = parseFloat(seconds.toFixed(3)); + } + break; + } + default: + break; + } + } + + goTo(event: MouseEvent): void { + const cursorPosition = + event.clientX - + (this._sliderNode.getBoundingClientRect().left + + document.documentElement.scrollLeft); + + const seconds = this.getSecondsFromPosition(cursorPosition); + + this._audio[0].currentTime = seconds; + } + + setVolume(event: InputEvent): void { + this._volume = parseFloat((event.target as HTMLInputElement).value); + this._audio[0].volume = this._volume; + } + + setCurrentTime(currentTime: number): void { + const seekingTimePosition = this.getPositionFromSeconds(currentTime); + const startTimePosition = this.getPositionFromSeconds(this._clip.startTime); + const seekingTimeSegmentPosition = seekingTimePosition - startTimePosition; + const seekingTimePercentage = + (seekingTimeSegmentPosition / this._segmentContentNode.clientWidth) * + this._segmentContentNode.clientWidth; + + this._progressNode.style.transform = `translateX(${seekingTimeSegmentPosition}px)`; + this._seekingNode.style.transform = `scaleX(${seekingTimePercentage})`; + } + + setAction(event: MouseEvent, action: Action): void { + switch (action.type) { + case ActionType.StretchLeft: + action.payload = { + offset: + this._segmentHandleNodes[0].getBoundingClientRect().right - + event.clientX, + }; + break; + case ActionType.StretchRight: + action.payload = { + offset: + this._segmentHandleNodes[1].getBoundingClientRect().left - + event.clientX, + }; + break; + default: + break; + } + this._action = action; + } + + private secondsToHHMMSS(seconds: number): string { + return new Date(seconds * 1000).toISOString().substr(11, 8); + } + + trim(side: "start" | "end") { + if (side === "start") { + this._clip = { + startTime: parseFloat(this._audio[0].currentTime.toFixed(3)), + endTime: this._clip.endTime, + }; + } else { + this._clip = { + startTime: this._clip.startTime, + endTime: this._currentTime, + }; + } + } + + static styles = css` + .slider-wrapper { + position: relative; + width: 100%; + background-color: #0f172a; + } + + .buffering-bar { + position: absolute; + width: 100%; + height: 4px; + background-color: gray; + bottom: -4px; + left: 0; + } + + .slider { + position: absolute; + z-index: 10; + top: 0; + left: 0; + display: flex; + align-items: center; + height: 100%; + width: 100%; + } + + .slider__segment--wrapper { + position: absolute; + height: 100%; + } + + .slider__segment { + position: relative; + display: flex; + height: 120%; + top: -10%; + } + + .slider__segment-content { + box-sizing: border-box; + background-color: rgba(255, 255, 255, 0.5); + height: 100%; + width: 1px; + border-top: 2px dashed #b91c1c; + border-bottom: 2px dashed #b91c1c; + } + + .slider__seeking-placeholder { + position: absolute; + pointer-events: none; + background-color: rgba(255, 255, 255, 0.5); + height: 100%; + width: 1px; + transform-origin: left; + } + + .slider__segment-progress-handle { + position: absolute; + width: 20px; + height: 20px; + top: -50%; + left: -10px; + margin-top: -2px; + background-color: #3b82f6; + border-radius: 50%; + box-shadow: 0 0 0 2px #ffffff; + } + + .slider__segment-progress-handle::after { + position: absolute; + content: ""; + width: 0px; + height: 0px; + bottom: -12px; + left: 0; + border: 10px solid transparent; + border-top-color: transparent; + border-top-style: solid; + border-top-width: 10px; + border-top: 10px solid #3b82f6; + } + + .slider__segment-progress-handle--ghost { + opacity: 0.5; + } + + .slider__segment .slider__segment-handle { + position: absolute; + width: 1rem; + height: 100%; + background-color: #b91c1c; + border: none; + margin: auto 0; + top: 0; + bottom: 0; + } + + .slider__segment .slider__segment-handle::before { + content: ""; + position: absolute; + height: 50%; + width: 2px; + background-color: #ffffff; + margin: auto; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + + .slider__segment .clipper__handle-left { + left: -1rem; + border-radius: 0.2rem 0 0 0.2rem; + } + + .slider__segment .slider__segment-handle span { + opacity: 0; + pointer-events: none; + position: absolute; + left: -100%; + top: -30%; + background-color: #0f172a; + color: #ffffff; + padding: 0 0.25rem; + } + + .slider__segment .clipper__handle-right { + right: -1rem; + border-radius: 0 0.2rem 0.2rem 0; + } + + .toolbar { + display: flex; + align-items: center; + padding: 0.5rem 0.5rem 0.25rem 0.5rem; + justify-content: space-between; + background-color: hsl(var(--color-background-elevated)); + box-shadow: + 0 1px 3px 0 rgb(0 0 0 / 0.1), + 0 1px 2px -1px rgb(0 0 0 / 0.1); + border-radius: 0 0 0.75rem 0.75rem; + flex-wrap: wrap; + gap: 0.5rem; + } + + .toolbar__audio-controls { + display: flex; + align-items: center; + gap: 0.5rem; + } + + .toolbar .toolbar__play-button { + padding: 0.5rem; + height: 32px; + width: 32px; + font-size: 1em; + } + + .toolbar__trim-controls { + display: flex; + align-items: center; + gap: 0.5rem; + flex-shrink: 0; + } + + .toolbar button { + cursor: pointer; + background-color: hsl(var(--color-accent-base)); + color: hsl(var(--color-accent-contrast)); + border-radius: 9999px; + border: none; + padding: 0.25rem 0.5rem; + box-shadow: + 0 1px 3px 0 rgb(0 0 0 / 0.1), + 0 1px 2px -1px rgb(0 0 0 / 0.1); + } + + .toolbar button:hover { + background-color: hsl(var(--color-accent-hover)); + } + + .toolbar button:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 + var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 + calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: + var(--tw-ring-offset-shadow), + var(--tw-ring-shadow), + 0 0 rgba(0, 0, 0, 0); + box-shadow: + var(--tw-ring-offset-shadow), + var(--tw-ring-shadow), + 0 0 rgba(0, 0, 0, 0); + box-shadow: + var(--tw-ring-offset-shadow), var(--tw-ring-shadow), + var(--tw-shadow, 0 0 rgba(0, 0, 0, 0)); + --tw-ring-offset-width: 2px; + --tw-ring-opacity: 1; + --tw-ring-color: hsl(var(--color-accent-base) / var(--tw-ring-opacity)); + --tw-ring-offset-color: hsl(var(--color-background-base)); + } + + .toolbar__trim-controls button { + font-weight: 600; + font-family: + Inter, + ui-sans-serif, + system-ui, + -apple-system, + Segoe UI, + Roboto, + Ubuntu, + Cantarell, + Noto Sans, + sans-serif, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + } + + .animate-spin { + animation: spin 1s linear infinite; + } + + @keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + .volume { + display: flex; + font-size: 1.2rem; + color: hsl(var(--color-accent-base)); + align-items: center; + gap: 0.25rem; + } + + .range-slider { + accent-color: hsl(var(--color-accent-base)); + width: 100px; + } + + time { + font-size: 0.875rem; + font-family: "Mono"; + } + `; + + render(): TemplateResult<1> { + return html` + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    + + + + + + + +
    + +
    +
    + + +
    +
    + `; + } +} diff --git a/resources/js/_modules/code-editor.ts b/resources/js/_modules/code-editor.ts new file mode 100644 index 00000000..446752ca --- /dev/null +++ b/resources/js/_modules/code-editor.ts @@ -0,0 +1,229 @@ +import { indentWithTab } from "@codemirror/commands"; +import { html as htmlLang } from "@codemirror/lang-html"; +import { xml } from "@codemirror/lang-xml"; +import { + defaultHighlightStyle, + syntaxHighlighting, +} from "@codemirror/language"; +import { Compartment, EditorState, Extension } from "@codemirror/state"; +import { keymap, ViewUpdate } from "@codemirror/view"; +import { basicSetup, EditorView } from "codemirror"; +import { prettify as prettifyHTML, minify as minifyHTML } from "htmlfy"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { + customElement, + property, + queryAssignedNodes, + state, +} from "lit/decorators.js"; +import xmlFormat from "xml-formatter"; + +const language = new Compartment(); + +@customElement("code-editor") +export class XMLEditor extends LitElement { + @queryAssignedNodes({ slot: "textarea" }) + _textarea!: NodeListOf; + + @property() + lang = "html"; + + @state() + editorState!: EditorState; + + @state() + editorView!: EditorView; + + _textareaEvents = [ + { + events: ["focus", "invalid"], + onEvent: (_: Event, editor: EditorView) => { + // focus editor when textarea is focused or invalid + editor.focus(); + }, + }, + ]; + + firstUpdated(): void { + const minHeightEditor = EditorView.baseTheme({ + ".cm-content, .cm-gutter": { + minHeight: this._textarea[0].clientHeight + "px", + }, + }); + + const extensions: Extension[] = [ + basicSetup, + keymap.of([indentWithTab]), + minHeightEditor, + syntaxHighlighting(defaultHighlightStyle), + EditorView.updateListener.of((viewUpdate: ViewUpdate) => { + if (viewUpdate.docChanged) { + // Document changed, minify and update textarea value + switch (this.lang) { + case "xml": + this._textarea[0].value = minifyXML( + viewUpdate.state.doc.toString() + ); + break; + case "html": + this._textarea[0].value = minifyHTML( + viewUpdate.state.doc.toString() + ); + break; + default: + this._textarea[0].value = viewUpdate.state.doc.toString(); + break; + } + } + }), + ]; + + let editorContents = ""; + switch (this.lang) { + case "xml": + editorContents = formatXML(this._textarea[0].value); + extensions.push(language.of(xml())); + break; + case "html": + editorContents = prettifyHTML(this._textarea[0].value); + extensions.push(language.of(htmlLang())); + break; + default: + break; + } + + this.editorState = EditorState.create({ + doc: editorContents, + extensions: extensions, + }); + + this.editorView = new EditorView({ + state: this.editorState, + root: this.shadowRoot as ShadowRoot, + parent: this.shadowRoot as ShadowRoot, + }); + + // hide textarea + this._textarea[0].style.position = "absolute"; + this._textarea[0].style.opacity = "0"; + this._textarea[0].style.zIndex = "-9999"; + this._textarea[0].style.pointerEvents = "none"; + + for (const event of this._textareaEvents) { + event.events.forEach((name) => { + this._textarea[0].addEventListener(name, (e) => + event.onEvent(e, this.editorView) + ); + }); + } + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + for (const event of this._textareaEvents) { + event.events.forEach((name) => { + this._textarea[0].removeEventListener(name, (e) => + event.onEvent(e, this.editorView) + ); + }); + } + } + + static styles = css` + .cm-editor { + border-radius: 0.5rem; + overflow: hidden; + border: 3px solid hsl(var(--color-border-contrast)); + background-color: hsl(var(--color-background-elevated)); + transition-property: + color, + background-color, + border-color, + text-decoration-color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + } + .cm-editor.cm-focused { + outline: 2px solid transparent; + box-shadow: + 0 0 0 2px hsl(var(--color-background-elevated)), + 0 0 0 calc(4px) hsl(var(--color-accent-base)); + } + .cm-gutters { + background-color: hsl(var(--color-background-elevated)) !important; + } + + .cm-activeLine { + background-color: hsla( + var(--color-background-highlight) / 0.25 + ) !important; + } + + .cm-activeLineGutter { + background-color: hsl(var(--color-background-highlight)) !important; + } + + .ͼ4 .cm-line { + caret-color: hsl(var(--color-text-base)) !important; + } + + .ͼ1 .cm-cursor { + border: none; + } + `; + + render(): TemplateResult<1> { + return html``; + } +} + +function formatXML(contents: string) { + if (contents === "") { + return contents; + } + + try { + return xmlFormat(contents, { + indentation: " ", + }); + } catch { + // xml doesn't have a root node + const editorContents = xmlFormat("" + contents + "", { + indentation: " ", + }); + // remove root, unnecessary lines and indents + return editorContents + .replace(/^/, "") + .replace(/<\/root>$/, "") + .replace(/^\s*[\r\n]/gm, "") + .replace(/[\r\n] {2}/gm, "\r\n") + .trim(); + } +} + +function minifyXML(contents: string) { + if (contents === "") { + return contents; + } + + try { + return xmlFormat.minify(contents, { + collapseContent: true, + }); + } catch { + const minifiedContent = xmlFormat.minify(`${contents}`, { + collapseContent: true, + }); + // remove root + return minifiedContent.replace(/^/, "").replace(/<\/root>$/, ""); + } +} diff --git a/resources/js/_modules/markdown-preview.ts b/resources/js/_modules/markdown-preview.ts new file mode 100644 index 00000000..e2a37612 --- /dev/null +++ b/resources/js/_modules/markdown-preview.ts @@ -0,0 +1,83 @@ +import MarkdownToolbarElement from "@github/markdown-toolbar-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { marked } from "marked"; + +@customElement("markdown-preview") +export class MarkdownPreview extends LitElement { + @property() + for!: string; + + @property({ attribute: false }) + _textarea!: HTMLTextAreaElement; + + @property({ attribute: false }) + _markdownToolbar!: MarkdownToolbarElement; + + @state() + _show = false; + + connectedCallback(): void { + super.connectedCallback(); + + this._textarea = document.getElementById(this.for) as HTMLTextAreaElement; + this._markdownToolbar = document.querySelector( + `markdown-toolbar[for=${this.for}]` + ) as MarkdownToolbarElement; + } + + hide(): void { + this._show = false; + this.classList.add("hidden"); + this._markdownToolbar.classList.remove("hidden"); + } + + show(): void { + this._show = true; + this.classList.remove("hidden"); + this._markdownToolbar.classList.add("hidden"); + } + + markdownToHtml(): string { + const renderer = new marked.Renderer(); + renderer.link = function () { + // eslint-disable-next-line prefer-rest-params, @typescript-eslint/no-explicit-any + const link = marked.Renderer.prototype.link.apply(this, arguments as any); + return link.replace(" { + return unsafe + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); + }; + + static styles = css` + * { + max-width: 65ch; + } + + a { + font-weight: 600; + color: hsl(var(--color-accent-base)); + text-decoration: none; + } + `; + + render(): TemplateResult<1> { + return html`${this._show + ? html`${unsafeHTML(this.markdownToHtml())}
    ` + : html``}`; + } +} diff --git a/resources/js/_modules/markdown-write-preview.ts b/resources/js/_modules/markdown-write-preview.ts new file mode 100644 index 00000000..9de3795e --- /dev/null +++ b/resources/js/_modules/markdown-write-preview.ts @@ -0,0 +1,79 @@ +import { css, html, LitElement, TemplateResult } from "lit"; +import { + customElement, + property, + queryAssignedElements, +} from "lit/decorators.js"; +import { MarkdownPreview } from "./markdown-preview"; + +@customElement("markdown-write-preview") +export class MarkdownWritePreview extends LitElement { + @property() + for!: string; + + @property({ attribute: false }) + _textarea: HTMLTextAreaElement | null = null; + + @property({ attribute: false }) + _markdownPreview!: MarkdownPreview; + + @queryAssignedElements({ slot: "write", flatten: true }) + _write!: Array; + + @queryAssignedElements({ slot: "preview", flatten: true }) + _preview!: Array; + + connectedCallback(): void { + super.connectedCallback(); + + this._textarea = document.getElementById(this.for) as HTMLTextAreaElement; + this._markdownPreview = document.querySelector( + `markdown-preview[for=${this.for}]` + ) as MarkdownPreview; + } + + firstUpdated(): void { + this.write(); + } + + write(): void { + this._markdownPreview.hide(); + this._write[0].classList.add("active"); + this._preview[0].classList.remove("active"); + } + + preview(): void { + this._markdownPreview.show(); + this._preview[0].classList.add("active"); + this._write[0].classList.remove("active"); + } + + static styles = css` + ::slotted(button) { + opacity: 0.5; + } + + ::slotted(button.active) { + position: relative; + opacity: 1; + } + + ::slotted(button.active)::after { + content: ""; + position: absolute; + bottom: -2px; + left: 0; + right: 0; + width: 80%; + height: 4px; + margin: 0 auto; + background-color: hsl(var(--color-accent-base)); + border-radius: 9999px; + } + `; + + render(): TemplateResult<1> { + return html` + `; + } +} diff --git a/resources/js/_modules/permalink-edit.ts b/resources/js/_modules/permalink-edit.ts new file mode 100644 index 00000000..c0ea0224 --- /dev/null +++ b/resources/js/_modules/permalink-edit.ts @@ -0,0 +1,224 @@ +import "@github/clipboard-copy-element"; +import ClipboardCopyElement from "@github/clipboard-copy-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { + customElement, + property, + query, + queryAssignedElements, + state, +} from "lit/decorators.js"; + +@customElement("permalink-edit") +export class PermalinkEdit extends LitElement { + @queryAssignedElements({ slot: "domain", flatten: true }) + _domain!: NodeListOf; + + @queryAssignedElements({ slot: "slug-input", flatten: true }) + _slugInput!: NodeListOf; + + @query("clipboard-copy") + _clipboardCopy!: ClipboardCopyElement; + + @property({ attribute: "edit-label" }) + editLabel = "Edit"; + + @property({ attribute: "copy-label" }) + copyLabel = "Copy"; + + @property({ attribute: "permalink-base" }) + permalinkBase = ""; + + @state() + isEditable = false; + + @state() + permalink = ""; + + @state() + slugInputEvents = [ + { + name: "change", + onEvent: (): void => { + this.setPermalink(); + }, + }, + { + name: "focus", + onEvent: (): void => { + this.editSlug(); + }, + }, + { + name: "focusin", + onEvent: (event: Event): void => { + setTimeout(() => { + (event.target as HTMLInputElement).selectionStart = ( + event.target as HTMLInputElement + ).selectionEnd = 10000; + }, 0); + }, + }, + { + name: "focusout", + onEvent: (): void => { + this.stopEdit(); + }, + }, + ]; + + connectedCallback(): void { + super.connectedCallback(); + } + + firstUpdated(): void { + console.log(this._slugInput); + + this.permalinkBase += this.permalinkBase.endsWith("/") ? "" : "/"; + + // set permalink value + this.setPermalink(); + + this._clipboardCopy.addEventListener("clipboard-copy", (event: Event) => { + const notice = (event.target as HTMLDivElement).querySelector( + ".notice" + ) as HTMLSpanElement; + if (notice) { + notice.hidden = false; + setTimeout(() => { + notice.hidden = true; + }, 1000); + } + }); + + this._slugInput[0].readOnly = !this.isEditable; + this.slugInputEvents.forEach((slugInputEvent) => { + this._slugInput[0].addEventListener( + slugInputEvent.name, + slugInputEvent.onEvent + ); + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this.slugInputEvents.forEach((slugInputEvent) => { + this._slugInput[0].removeEventListener( + slugInputEvent.name, + slugInputEvent.onEvent + ); + }); + + this._clipboardCopy.removeEventListener( + "clipboard-copy", + (event: Event) => { + const notice = (event.target as HTMLDivElement).querySelector( + ".notice" + ) as HTMLSpanElement; + if (notice) { + notice.hidden = false; + setTimeout(() => { + notice.hidden = true; + }, 1000); + } + } + ); + } + + editSlug(): void { + this.isEditable = true; + this._slugInput[0].readOnly = !this.isEditable; + this._slugInput[0].focus(); + } + + stopEdit(): void { + this.isEditable = false; + this._slugInput[0].readOnly = !this.isEditable; + } + + setPermalink(): void { + this.permalink = this.permalinkBase + this._slugInput[0].value; + } + + static styles = css` + ::slotted(input[slot="slug-input"][readonly]) { + background-color: transparent !important; + border-color: transparent !important; + padding-left: 0 !important; + margin-left: -0.25rem !important; + font-weight: 600 !important; + } + + ::slotted([slot="domain"]) { + margin-right: 0.25rem; + } + + button, + clipboard-copy { + background: transparent; + border: none; + padding: 0.25rem; + cursor: pointer; + } + + button svg, + clipboard-copy svg { + fill: hsl(var(--color-text-base)); + opacity: 0.6; + font-size: 1.25rem; + } + + button:hover svg, + clipboard-copy:hover svg { + opacity: 1; + } + + clipboard-copy { + position: relative; + } + + .notice { + position: absolute; + background-color: black; + color: #ffffff; + bottom: -1rem; + right: 0; + font-size: 0.75rem; + padding: 0 0.25rem; + } + `; + + render(): TemplateResult<1> { + return html`${this + .isEditable + ? "" + : html` `} + + + + + + `; + } +} diff --git a/resources/js/_modules/play-episode-button.ts b/resources/js/_modules/play-episode-button.ts new file mode 100644 index 00000000..101868ad --- /dev/null +++ b/resources/js/_modules/play-episode-button.ts @@ -0,0 +1,277 @@ +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +@customElement("play-episode-button") +export class PlayEpisodeButton extends LitElement { + @property() + id = "0"; + + @property() + src = ""; + + @property() + mediaType = ""; + + @property() + title!: string; + + @property() + podcast!: string; + + @property() + imageSrc!: string; + + @property() + playLabel!: string; + + @property() + playingLabel!: string; + + @property({ attribute: false }) + _castopodAudioPlayer!: HTMLDivElement; + + @property({ attribute: false }) + _audio!: HTMLAudioElement; + + @state() + isPlaying!: boolean; + + @state() + _playbackSpeed = 1; + + @state() + _events = [ + { + name: "canplay", + onEvent: (event: Event): void => { + (event.target as HTMLAudioElement)?.play(); + }, + }, + { + name: "play", + onEvent: (): void => { + this.isPlaying = true; + }, + }, + { + name: "pause", + onEvent: (): void => { + this.isPlaying = false; + }, + }, + { + name: "ratechange", + onEvent: (event: Event): void => { + this._playbackSpeed = (event.target as HTMLAudioElement)?.playbackRate; + }, + }, + ]; + + async connectedCallback(): Promise { + super.connectedCallback(); + + await this._elementReady("div[id=castopod-audio-player]"); + await this._elementReady("div[id=castopod-audio-player] audio"); + + this._castopodAudioPlayer = document.body.querySelector( + "div[id=castopod-audio-player]" + ) as HTMLDivElement; + + this._audio = this._castopodAudioPlayer.querySelector( + "audio" + ) as HTMLAudioElement; + } + + private _elementReady(selector: string) { + return new Promise((resolve) => { + const element = document.querySelector(selector); + if (element) { + resolve(element); + } + new MutationObserver((_, observer) => { + // Query for elements matching the specified selector + Array.from(document.querySelectorAll(selector)).forEach((element) => { + resolve(element); + //Once we have resolved we don't need the observer anymore. + observer.disconnect(); + }); + }).observe(document.documentElement, { + childList: true, + subtree: true, + }); + }); + } + + play(): void { + const currentlyPlayingEpisode = this._castopodAudioPlayer.dataset.episode; + + const isCurrentEpisode = currentlyPlayingEpisode === this.id; + + if (currentlyPlayingEpisode === "-1") { + this._showPlayer(); + } + + if (isCurrentEpisode) { + this._audio.play(); + } else { + const playingEpisodeButton = document.querySelector( + `play-episode-button[id="${currentlyPlayingEpisode}"]` + ) as PlayEpisodeButton; + if (playingEpisodeButton) { + this._flushLastPlayButton(playingEpisodeButton); + } + + this._loadEpisode(); + } + } + + pause(): void { + this._audio.pause(); + } + + private _showPlayer(): void { + this._castopodAudioPlayer.style.display = ""; + document.body.classList.add("pb-[105px]", "sm:pb-[52px]"); + } + + private _flushLastPlayButton(playingEpisodeButton: PlayEpisodeButton): void { + playingEpisodeButton.isPlaying = false; + + for (const event of playingEpisodeButton._events) { + playingEpisodeButton._audio.removeEventListener( + event.name, + event.onEvent, + false + ); + } + + this._playbackSpeed = playingEpisodeButton._playbackSpeed; + } + + private _loadEpisode(): void { + this._castopodAudioPlayer.dataset.episode = this.id; + + this._audio.src = this.src; + this._audio.load(); + this._audio.playbackRate = this._playbackSpeed; + for (const event of this._events) { + this._audio.addEventListener(event.name, event.onEvent, false); + } + + const img: HTMLImageElement | null = + this._castopodAudioPlayer.querySelector("img"); + + if (img) { + img.src = this.imageSrc; + img.alt = this.title; + } + + const episodeTitle: HTMLParagraphElement | null = + this._castopodAudioPlayer.querySelector('p[id="castopod-player-title"]'); + + if (episodeTitle) { + episodeTitle.title = this.title; + episodeTitle.innerHTML = this.title; + } + + const podcastTitle: HTMLParagraphElement | null = + this._castopodAudioPlayer.querySelector( + 'p[id="castopod-player-podcast"]' + ); + + if (podcastTitle) { + podcastTitle.title = this.podcast; + podcastTitle.innerHTML = this.podcast; + } + } + + static styles = css` + button { + background-color: hsl(var(--color-accent-base)); + cursor: pointer; + display: inline-flex; + align-items: center; + padding: 0.5rem 0.5rem; + font-size: 0.875rem; + line-height: 1.25rem; + border: 2px solid transparent; + border-radius: 9999px; + + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + } + + button:hover { + background-color: hsl(var(--color-accent-hover)); + } + + button:focus { + outline: none; + box-shadow: + 0 0 0 2px hsl(var(--color-background-base)), + 0 0 0 4px hsl(var(--color-accent-base)); + } + + button.playing { + background-color: hsl(var(--color-background-base)); + border: 2px solid hsl(var(--color-accent-base)); + } + + button.playing:hover { + background-color: hsl(var(--color-background-elevated)); + } + + button.playing svg { + color: hsl(var(--color-accent-base)); + } + + svg { + font-size: 1.5rem; + color: hsl(var(--color-accent-contrast)); + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } + + .animate-spin { + animation: spin 3s linear infinite; + } + `; + + render(): TemplateResult<1> { + return html``; + } +} diff --git a/resources/js/_modules/play-soundbite.ts b/resources/js/_modules/play-soundbite.ts new file mode 100644 index 00000000..098a73a9 --- /dev/null +++ b/resources/js/_modules/play-soundbite.ts @@ -0,0 +1,194 @@ +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +@customElement("play-soundbite") +export class PlaySoundbite extends LitElement { + @property({ attribute: "audio-src" }) + audioSrc!: string; + + @property({ type: Number, attribute: "start-time" }) + startTime!: number; + + @property({ type: Number }) + duration!: number; + + @property({ attribute: "play-label" }) + playLabel!: string; + + @property({ attribute: "playing-label" }) + playingLabel!: string; + + @state() + _audio: HTMLAudioElement | null = null; + + @state() + _isPlaying = false; + + @state() + _isLoading = false; + + _audioEvents = [ + { + name: "play", + onEvent: () => { + this._isPlaying = true; + }, + }, + { + name: "pause", + onEvent: () => { + this._isPlaying = false; + }, + }, + { + name: "timeupdate", + onEvent: () => { + if (this._audio) { + if (this._audio.currentTime < this.startTime) { + this._isLoading = true; + this._audio.currentTime = this.startTime; + } else if (this._audio.currentTime > this.startTime + this.duration) { + this.stopSoundbite(); + } else { + this._isLoading = false; + } + } + }, + }, + ]; + + playSoundbite() { + if (this._audio === null) { + this._audio = new Audio(this.audioSrc); + for (const event of this._audioEvents) { + this._audio.addEventListener(event.name, event.onEvent); + } + } + + this._audio.currentTime = this.startTime; + this._audio.play(); + } + + stopSoundbite() { + if (this._audio !== null) { + this._audio.pause(); + this._audio.currentTime = this.startTime; + } + } + + disconnectedCallback(): void { + if (this._audio) { + for (const event of this._audioEvents) { + this._audio.removeEventListener(event.name, event.onEvent); + } + } + } + + static styles = css` + button { + background-color: hsl(var(--color-accent-base)); + cursor: pointer; + display: inline-flex; + align-items: center; + padding: 0.5rem; + font-size: 0.875rem; + border: 2px solid transparent; + border-radius: 9999px; + + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + } + + button:hover { + background-color: hsl(var(--color-accent-hover)); + } + + button:focus { + outline: none; + box-shadow: + 0 0 0 2px hsl(var(--color-background-base)), + 0 0 0 4px hsl(var(--color-accent-base)); + } + + button.playing { + background-color: hsl(var(--color-background-base)); + border: 2px solid hsl(var(--color-accent-base)); + } + + button.playing:hover { + background-color: hsl(var(--color-background-elevated)); + } + + button.playing svg { + color: hsl(var(--color-accent-base)); + } + + svg { + color: hsl(var(--color-accent-contrast)); + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } + + .animate-spin { + animation: spin 3s linear infinite; + } + `; + + render(): TemplateResult<1> { + return html``; + } +} diff --git a/resources/js/_modules/video-clip-previewer.ts b/resources/js/_modules/video-clip-previewer.ts new file mode 100644 index 00000000..34e68335 --- /dev/null +++ b/resources/js/_modules/video-clip-previewer.ts @@ -0,0 +1,138 @@ +import { css, html, LitElement, TemplateResult } from "lit"; +import { + customElement, + property, + queryAssignedElements, +} from "lit/decorators.js"; +import { styleMap } from "lit/directives/style-map.js"; + +enum VideoFormats { + Landscape = "landscape", + Portrait = "portrait", + Squared = "squared", +} + +const formatMap = { + [VideoFormats.Landscape]: "16/9", + [VideoFormats.Portrait]: "9/16", + [VideoFormats.Squared]: "1/1", +}; + +@customElement("video-clip-previewer") +export class VideoClipPreviewer extends LitElement { + @queryAssignedElements({ slot: "preview_image", flatten: true }) + _image!: NodeListOf; + + @property() + title = ""; + + @property() + format: VideoFormats = VideoFormats.Portrait; + + @property() + theme = "172 100% 17%"; + + @property({ type: Number }) + duration!: number; + + @property({ attribute: false }) + _previewImage!: HTMLImageElement; + + protected firstUpdated(): void { + this._previewImage = this._image[0].cloneNode(true) as HTMLImageElement; + this._previewImage.classList.add("preview-bg"); + } + + private secondsToHHMMSS(seconds: number) { + // Adapted from https://stackoverflow.com/a/34841026 + const h = Math.floor(seconds / 3600); + const min = Math.floor(seconds / 60) % 60; + const s = seconds % 60; + + return [h, min, s] + .map((v) => (v < 10 ? "0" + v : v)) + .filter((v, i) => v !== "00" || i > 0) + .join(":"); + } + + static styles = css` + .metadata { + position: absolute; + top: 1rem; + left: 1.5rem; + color: #ffffff; + display: flex; + flex-direction: column; + } + + .title { + font-family: "Kumbh Sans"; + font-weight: 900; + font-size: 1.5rem; + text-shadow: 2px 3px 5px rgba(0, 0, 0, 0.5); + } + + .duration { + font-family: "Inter"; + font-weight: 600; + } + + .preview-bg { + position: absolute; + background-color: red; + width: 100%; + object-fit: cover; + filter: blur(30px); + opacity: 0.5; + } + + .video-background { + position: relative; + display: grid; + justify-items: center; + align-items: center; + background-color: black; + width: 100%; + aspect-ratio: 16 / 9; + border-radius: 0.75rem 0.75rem 0 0; + overflow: hidden; + } + + .video-format { + z-index: 10; + display: grid; + align-items: center; + justify-items: center; + height: 100%; + border: 4px solid hsl(0 0% 100% / 0.5); + transition: 300ms ease-in-out aspect-ratio; + } + + ::slotted(img) { + border-radius: 0.5rem; + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 0.1), + 0 2px 4px -2px rgb(0 0 0 / 0.1); + } + `; + + render(): TemplateResult<1> { + const styles = { + aspectRatio: formatMap[this.format], + backgroundColor: `hsl(${this.theme})`, + }; + + return html`
    + ${this._previewImage} +
    + + +
    +
    `; + } +} diff --git a/resources/js/admin-audio-player.ts b/resources/js/admin-audio-player.ts new file mode 100644 index 00000000..7fa61b86 --- /dev/null +++ b/resources/js/admin-audio-player.ts @@ -0,0 +1,79 @@ +import { + VmAudio, + VmCaptions, + VmClickToPlay, + VmControl, + VmControls, + VmCurrentTime, + VmDefaultControls, + VmDefaultSettings, + VmDefaultUi, + VmEndTime, + VmFile, + VmIcon, + VmIconLibrary, + VmLoadingScreen, + VmMenu, + VmMenuItem, + VmMenuRadio, + VmMenuRadioGroup, + VmMuteControl, + VmPlaybackControl, + VmPlayer, + VmScrubberControl, + VmSettings, + VmSettingsControl, + VmSkeleton, + VmSlider, + VmSubmenu, + VmTime, + VmTimeProgress, + VmTooltip, + VmUi, + VmVolumeControl, +} from "@vime/core"; +import "@vime/core/themes/default.css"; +import "@vime/core/themes/light.css"; +import "./_modules/play-episode-button"; + +// Register Castopod's vm player icons library +const library: HTMLVmIconLibraryElement | null = document.querySelector( + 'vm-icon-library[name="castopod-vm-player-icons"]' +); +if (library) { + library.resolver = (iconName) => `/assets/vm-player-icons/${iconName}.svg`; +} + +// Vime elements for audio player +customElements.define("vm-player", VmPlayer); +customElements.define("vm-file", VmFile); +customElements.define("vm-audio", VmAudio); +customElements.define("vm-ui", VmUi); +customElements.define("vm-default-ui", VmDefaultUi); +customElements.define("vm-click-to-play", VmClickToPlay); +customElements.define("vm-captions", VmCaptions); +customElements.define("vm-loading-screen", VmLoadingScreen); +customElements.define("vm-default-controls", VmDefaultControls); +customElements.define("vm-default-settings", VmDefaultSettings); +customElements.define("vm-controls", VmControls); +customElements.define("vm-playback-control", VmPlaybackControl); +customElements.define("vm-volume-control", VmVolumeControl); +customElements.define("vm-scrubber-control", VmScrubberControl); +customElements.define("vm-current-time", VmCurrentTime); +customElements.define("vm-end-time", VmEndTime); +customElements.define("vm-settings-control", VmSettingsControl); +customElements.define("vm-time-progress", VmTimeProgress); +customElements.define("vm-control", VmControl); +customElements.define("vm-icon", VmIcon); +customElements.define("vm-icon-library", VmIconLibrary); +customElements.define("vm-tooltip", VmTooltip); +customElements.define("vm-mute-control", VmMuteControl); +customElements.define("vm-slider", VmSlider); +customElements.define("vm-time", VmTime); +customElements.define("vm-menu", VmMenu); +customElements.define("vm-menu-item", VmMenuItem); +customElements.define("vm-submenu", VmSubmenu); +customElements.define("vm-menu-radio-group", VmMenuRadioGroup); +customElements.define("vm-menu-radio", VmMenuRadio); +customElements.define("vm-settings", VmSettings); +customElements.define("vm-skeleton", VmSkeleton); diff --git a/resources/js/admin.ts b/resources/js/admin.ts new file mode 100644 index 00000000..bc87479d --- /dev/null +++ b/resources/js/admin.ts @@ -0,0 +1,43 @@ +import "@github/markdown-toolbar-element"; +import "@github/relative-time-element"; +import "./_modules/audio-clipper"; +import ClientTimezone from "./_modules/ClientTimezone"; +import Clipboard from "./_modules/Clipboard"; +import DateTimePicker from "./_modules/DateTimePicker"; +import Dropdown from "./_modules/Dropdown"; +import HotKeys from "./_modules/HotKeys"; +import "./_modules/markdown-preview"; +import "./_modules/markdown-write-preview"; +import SelectMulti from "./_modules/SelectMulti"; +import "./_modules/permalink-edit"; +import "./_modules/play-soundbite"; +import PublishMessageWarning from "./_modules/PublishMessageWarning"; +import Select from "./_modules/Select"; +import SidebarToggler from "./_modules/SidebarToggler"; +import Slugify from "./_modules/Slugify"; +import ThemePicker from "./_modules/ThemePicker"; +import Time from "./_modules/Time"; +import Tooltip from "./_modules/Tooltip"; +import ValidateFileSize from "./_modules/ValidateFileSize"; +import "./_modules/video-clip-previewer"; +import VideoClipBuilder from "./_modules/VideoClipBuilder"; +import "./_modules/code-editor"; +import "@patternfly/elements/pf-tabs/pf-tabs.js"; +import FieldArray from "./_modules/FieldArray"; + +Dropdown(); +Tooltip(); +Select(); +SelectMulti(); +Slugify(); +SidebarToggler(); +ClientTimezone(); +DateTimePicker(); +Time(); +Clipboard(); +ThemePicker(); +PublishMessageWarning(); +HotKeys(); +ValidateFileSize(); +VideoClipBuilder(); +FieldArray(); diff --git a/resources/js/app.ts b/resources/js/app.ts new file mode 100644 index 00000000..65bf64d4 --- /dev/null +++ b/resources/js/app.ts @@ -0,0 +1,5 @@ +import Dropdown from "./_modules/Dropdown"; +import Tooltip from "./_modules/Tooltip"; + +Dropdown(); +Tooltip(); diff --git a/resources/js/audio-player.ts b/resources/js/audio-player.ts new file mode 100644 index 00000000..7c15480f --- /dev/null +++ b/resources/js/audio-player.ts @@ -0,0 +1,129 @@ +import { + VmAudio, + VmCaptions, + VmClickToPlay, + VmControl, + VmControls, + VmCurrentTime, + VmDefaultControls, + VmDefaultSettings, + VmDefaultUi, + VmEndTime, + VmFile, + VmIcon, + VmIconLibrary, + VmLoadingScreen, + VmMenu, + VmMenuItem, + VmMenuRadio, + VmMenuRadioGroup, + VmMuteControl, + VmPlaybackControl, + VmPlayer, + VmScrubberControl, + VmSettings, + VmSettingsControl, + VmSkeleton, + VmSlider, + VmSubmenu, + VmTime, + VmTimeProgress, + VmTooltip, + VmUi, + VmVolumeControl, +} from "@vime/core"; +import "@vime/core/themes/default.css"; +import "@vime/core/themes/light.css"; +import { html, render } from "lit"; +import "./_modules/play-episode-button"; + +const player = html``; + +render(player, document.body); + +// Register Castopod's vm player icons library +const library: HTMLVmIconLibraryElement | null = document.querySelector( + 'vm-icon-library[name="castopod-vm-player-icons"]' +); +if (library) { + library.resolver = (iconName) => `/assets/vm-player-icons/${iconName}.svg`; +} + +// Vime elements for audio player +customElements.define("vm-player", VmPlayer); +customElements.define("vm-file", VmFile); +customElements.define("vm-audio", VmAudio); +customElements.define("vm-ui", VmUi); +customElements.define("vm-default-ui", VmDefaultUi); +customElements.define("vm-click-to-play", VmClickToPlay); +customElements.define("vm-captions", VmCaptions); +customElements.define("vm-loading-screen", VmLoadingScreen); +customElements.define("vm-default-controls", VmDefaultControls); +customElements.define("vm-default-settings", VmDefaultSettings); +customElements.define("vm-controls", VmControls); +customElements.define("vm-playback-control", VmPlaybackControl); +customElements.define("vm-volume-control", VmVolumeControl); +customElements.define("vm-scrubber-control", VmScrubberControl); +customElements.define("vm-current-time", VmCurrentTime); +customElements.define("vm-end-time", VmEndTime); +customElements.define("vm-settings-control", VmSettingsControl); +customElements.define("vm-time-progress", VmTimeProgress); +customElements.define("vm-control", VmControl); +customElements.define("vm-icon", VmIcon); +customElements.define("vm-icon-library", VmIconLibrary); +customElements.define("vm-tooltip", VmTooltip); +customElements.define("vm-mute-control", VmMuteControl); +customElements.define("vm-slider", VmSlider); +customElements.define("vm-time", VmTime); +customElements.define("vm-menu", VmMenu); +customElements.define("vm-menu-item", VmMenuItem); +customElements.define("vm-submenu", VmSubmenu); +customElements.define("vm-menu-radio-group", VmMenuRadioGroup); +customElements.define("vm-menu-radio", VmMenuRadio); +customElements.define("vm-settings", VmSettings); +customElements.define("vm-skeleton", VmSkeleton); diff --git a/resources/js/charts.ts b/resources/js/charts.ts new file mode 100644 index 00000000..9b09ccaa --- /dev/null +++ b/resources/js/charts.ts @@ -0,0 +1,3 @@ +import DrawCharts from "./_modules/Charts"; + +DrawCharts(); diff --git a/resources/js/embed.ts b/resources/js/embed.ts new file mode 100644 index 00000000..d587cb7b --- /dev/null +++ b/resources/js/embed.ts @@ -0,0 +1,78 @@ +import { + VmAudio, + VmCaptions, + VmClickToPlay, + VmControl, + VmControls, + VmCurrentTime, + VmDefaultControls, + VmDefaultSettings, + VmDefaultUi, + VmEndTime, + VmFile, + VmIcon, + VmIconLibrary, + VmLoadingScreen, + VmMenu, + VmMenuItem, + VmMenuRadio, + VmMenuRadioGroup, + VmMuteControl, + VmPlaybackControl, + VmPlayer, + VmScrubberControl, + VmSettings, + VmSettingsControl, + VmSkeleton, + VmSlider, + VmSubmenu, + VmTime, + VmTimeProgress, + VmTooltip, + VmUi, + VmVolumeControl, +} from "@vime/core"; +import "@vime/core/themes/default.css"; +import "@vime/core/themes/light.css"; + +// Register Castopod's vm player icons library +const library: HTMLVmIconLibraryElement | null = document.querySelector( + 'vm-icon-library[name="castopod-vm-player-icons"]' +); +if (library) { + library.resolver = (iconName) => `/assets/vm-player-icons/${iconName}.svg`; +} + +// Vime elements for audio player +customElements.define("vm-player", VmPlayer); +customElements.define("vm-file", VmFile); +customElements.define("vm-audio", VmAudio); +customElements.define("vm-ui", VmUi); +customElements.define("vm-default-ui", VmDefaultUi); +customElements.define("vm-click-to-play", VmClickToPlay); +customElements.define("vm-captions", VmCaptions); +customElements.define("vm-loading-screen", VmLoadingScreen); +customElements.define("vm-default-controls", VmDefaultControls); +customElements.define("vm-default-settings", VmDefaultSettings); +customElements.define("vm-controls", VmControls); +customElements.define("vm-playback-control", VmPlaybackControl); +customElements.define("vm-volume-control", VmVolumeControl); +customElements.define("vm-scrubber-control", VmScrubberControl); +customElements.define("vm-current-time", VmCurrentTime); +customElements.define("vm-end-time", VmEndTime); +customElements.define("vm-settings-control", VmSettingsControl); +customElements.define("vm-time-progress", VmTimeProgress); +customElements.define("vm-control", VmControl); +customElements.define("vm-icon", VmIcon); +customElements.define("vm-icon-library", VmIconLibrary); +customElements.define("vm-tooltip", VmTooltip); +customElements.define("vm-mute-control", VmMuteControl); +customElements.define("vm-slider", VmSlider); +customElements.define("vm-time", VmTime); +customElements.define("vm-menu", VmMenu); +customElements.define("vm-menu-item", VmMenuItem); +customElements.define("vm-submenu", VmSubmenu); +customElements.define("vm-menu-radio-group", VmMenuRadioGroup); +customElements.define("vm-menu-radio", VmMenuRadio); +customElements.define("vm-settings", VmSettings); +customElements.define("vm-skeleton", VmSkeleton); diff --git a/resources/js/error.ts b/resources/js/error.ts new file mode 100644 index 00000000..1613e60d --- /dev/null +++ b/resources/js/error.ts @@ -0,0 +1,15 @@ +import "@github/clipboard-copy-element"; + +document.addEventListener("clipboard-copy", function (event) { + const button = event.target as HTMLButtonElement; + button.classList.add( + "[&>.copy-base]:hidden", + "[&>.copy-success]:inline-flex" + ); + setTimeout(() => { + button.classList.remove( + "[&>.copy-base]:hidden", + "[&>.copy-success]:inline-flex" + ); + }, 1000); +}); diff --git a/resources/js/install.ts b/resources/js/install.ts new file mode 100644 index 00000000..5f57a192 --- /dev/null +++ b/resources/js/install.ts @@ -0,0 +1,3 @@ +import Tooltip from "./_modules/Tooltip"; + +Tooltip(); diff --git a/resources/js/map.ts b/resources/js/map.ts new file mode 100644 index 00000000..2f3785e7 --- /dev/null +++ b/resources/js/map.ts @@ -0,0 +1,3 @@ +import DrawEpisodesMaps from "./_modules/EpisodesMap"; + +DrawEpisodesMaps(); diff --git a/resources/js/podcast.ts b/resources/js/podcast.ts new file mode 100644 index 00000000..f16c5618 --- /dev/null +++ b/resources/js/podcast.ts @@ -0,0 +1,10 @@ +import "@github/relative-time-element"; +import SidebarToggler from "./_modules/SidebarToggler"; +import Time from "./_modules/Time"; +import Toggler from "./_modules/Toggler"; +import Tooltip from "./_modules/Tooltip"; + +Time(); +Toggler(); +Tooltip(); +SidebarToggler(); diff --git a/resources/js/typings.d.ts b/resources/js/typings.d.ts new file mode 100644 index 00000000..f850e707 --- /dev/null +++ b/resources/js/typings.d.ts @@ -0,0 +1 @@ +declare module "leaflet.markercluster"; diff --git a/resources/js/vite-env.d.ts b/resources/js/vite-env.d.ts new file mode 100644 index 00000000..ff39e4c2 --- /dev/null +++ b/resources/js/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +declare module "*"; diff --git a/resources/static/fonts/inter-600.woff2 b/resources/static/fonts/inter-600.woff2 new file mode 100644 index 00000000..611e90c9 Binary files /dev/null and b/resources/static/fonts/inter-600.woff2 differ diff --git a/resources/static/fonts/inter-regular.woff2 b/resources/static/fonts/inter-regular.woff2 new file mode 100644 index 00000000..6c2b6893 Binary files /dev/null and b/resources/static/fonts/inter-regular.woff2 differ diff --git a/app/Resources/fonts/kumbh-sans-700.woff2 b/resources/static/fonts/kumbh-sans-700.woff2 similarity index 100% rename from app/Resources/fonts/kumbh-sans-700.woff2 rename to resources/static/fonts/kumbh-sans-700.woff2 diff --git a/app/Resources/fonts/kumbh-sans-regular.woff2 b/resources/static/fonts/kumbh-sans-regular.woff2 similarity index 100% rename from app/Resources/fonts/kumbh-sans-regular.woff2 rename to resources/static/fonts/kumbh-sans-regular.woff2 diff --git a/resources/static/fonts/noto-sans-mono-regular.woff2 b/resources/static/fonts/noto-sans-mono-regular.woff2 new file mode 100644 index 00000000..9c1e09db Binary files /dev/null and b/resources/static/fonts/noto-sans-mono-regular.woff2 differ diff --git a/resources/static/images/castopod-avatar.jpg b/resources/static/images/castopod-avatar.jpg new file mode 100644 index 00000000..c43999b0 Binary files /dev/null and b/resources/static/images/castopod-avatar.jpg differ diff --git a/resources/static/images/castopod-banner-amber.jpg b/resources/static/images/castopod-banner-amber.jpg new file mode 100644 index 00000000..65373352 Binary files /dev/null and b/resources/static/images/castopod-banner-amber.jpg differ diff --git a/resources/static/images/castopod-banner-crimson.jpg b/resources/static/images/castopod-banner-crimson.jpg new file mode 100644 index 00000000..3acd8e17 Binary files /dev/null and b/resources/static/images/castopod-banner-crimson.jpg differ diff --git a/resources/static/images/castopod-banner-jacaranda.jpg b/resources/static/images/castopod-banner-jacaranda.jpg new file mode 100644 index 00000000..d636d0c7 Binary files /dev/null and b/resources/static/images/castopod-banner-jacaranda.jpg differ diff --git a/resources/static/images/castopod-banner-lake.jpg b/resources/static/images/castopod-banner-lake.jpg new file mode 100644 index 00000000..982a362f Binary files /dev/null and b/resources/static/images/castopod-banner-lake.jpg differ diff --git a/resources/static/images/castopod-banner-onyx.jpg b/resources/static/images/castopod-banner-onyx.jpg new file mode 100644 index 00000000..ef5839d5 Binary files /dev/null and b/resources/static/images/castopod-banner-onyx.jpg differ diff --git a/resources/static/images/castopod-banner-pine.jpg b/resources/static/images/castopod-banner-pine.jpg new file mode 100644 index 00000000..b6ab145f Binary files /dev/null and b/resources/static/images/castopod-banner-pine.jpg differ diff --git a/resources/static/images/castopod-logo-base.svg b/resources/static/images/castopod-logo-base.svg new file mode 100644 index 00000000..72221cfa --- /dev/null +++ b/resources/static/images/castopod-logo-base.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/images/castopod-logo.svg b/resources/static/images/castopod-logo.svg new file mode 100644 index 00000000..55f4b22b --- /dev/null +++ b/resources/static/images/castopod-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/images/castopod-mascot_confused.svg b/resources/static/images/castopod-mascot_confused.svg new file mode 100644 index 00000000..89d51627 --- /dev/null +++ b/resources/static/images/castopod-mascot_confused.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Resources/images/marker/marker-icon-2x.png b/resources/static/images/marker/marker-icon-2x.png similarity index 100% rename from app/Resources/images/marker/marker-icon-2x.png rename to resources/static/images/marker/marker-icon-2x.png diff --git a/app/Resources/images/marker/marker-icon.png b/resources/static/images/marker/marker-icon.png similarity index 100% rename from app/Resources/images/marker/marker-icon.png rename to resources/static/images/marker/marker-icon.png diff --git a/app/Resources/images/marker/marker-shadow.png b/resources/static/images/marker/marker-shadow.png similarity index 100% rename from app/Resources/images/marker/marker-shadow.png rename to resources/static/images/marker/marker-shadow.png diff --git a/resources/static/vm-player-icons/check.svg b/resources/static/vm-player-icons/check.svg new file mode 100644 index 00000000..bf36197d --- /dev/null +++ b/resources/static/vm-player-icons/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/pause.svg b/resources/static/vm-player-icons/pause.svg new file mode 100644 index 00000000..ea2847b9 --- /dev/null +++ b/resources/static/vm-player-icons/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/play.svg b/resources/static/vm-player-icons/play.svg new file mode 100644 index 00000000..75ad8b10 --- /dev/null +++ b/resources/static/vm-player-icons/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/settings.svg b/resources/static/vm-player-icons/settings.svg new file mode 100644 index 00000000..a8cd5895 --- /dev/null +++ b/resources/static/vm-player-icons/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/volume-high.svg b/resources/static/vm-player-icons/volume-high.svg new file mode 100644 index 00000000..f352c50a --- /dev/null +++ b/resources/static/vm-player-icons/volume-high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/volume-low.svg b/resources/static/vm-player-icons/volume-low.svg new file mode 100644 index 00000000..999e6126 --- /dev/null +++ b/resources/static/vm-player-icons/volume-low.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/static/vm-player-icons/volume-mute.svg b/resources/static/vm-player-icons/volume-mute.svg new file mode 100644 index 00000000..44f6c50c --- /dev/null +++ b/resources/static/vm-player-icons/volume-mute.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/styles/_modules/breadcrumb.css b/resources/styles/_modules/breadcrumb.css new file mode 100644 index 00000000..b1ef8a30 --- /dev/null +++ b/resources/styles/_modules/breadcrumb.css @@ -0,0 +1,22 @@ +.breadcrumb { + @apply inline-flex flex-wrap px-1; +} + +.breadcrumb-item + .breadcrumb-item::before { + @apply inline-block px-1; + + color: hsl(var(--color-text-muted)); + content: "/"; +} + +.breadcrumb-item a { + @apply no-underline; + + &:hover { + @apply underline; + } +} + +.breadcrumb-item.active { + @apply font-semibold; +} diff --git a/resources/styles/_modules/choices.css b/resources/styles/_modules/choices.css new file mode 100644 index 00000000..a83a52f1 --- /dev/null +++ b/resources/styles/_modules/choices.css @@ -0,0 +1,355 @@ +/* =============================== += Choices = +=============================== */ + +@layer components { + .choices { + position: relative; + margin-bottom: 24px; + font-size: 16px; + } + + .choices:last-child { + margin-bottom: 0; + } + + .choices.is-disabled .choices__inner, + .choices.is-disabled .choices__input { + opacity: 0.5; + cursor: not-allowed; + user-select: none; + } + + .choices.is-disabled .choices__item { + cursor: not-allowed; + } + + .choices [hidden] { + position: absolute; + opacity: 0; + z-index: -9999; + pointer-events: none; + } + + .choices[data-type*="select-one"] { + cursor: pointer; + } + + .choices[data-type*="select-one"] .choices__input { + display: block; + width: 100%; + padding: 10px; + border-bottom: 1px solid hsl(var(--color-border-subtle)); + background-color: hsl(var(--color-background-elevated)); + margin: 0; + } + + .choices[data-type*="select-one"] .choices__button { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236B7280'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z'/%3E%3C/svg%3E"); + padding: 0; + background-size: 20px; + position: absolute; + top: 50%; + right: 0; + margin-top: -10px; + margin-right: 25px; + height: 20px; + width: 20px; + opacity: 0.5; + } + + .choices[data-type*="select-one"] .choices__button:hover, + .choices[data-type*="select-one"] .choices__button:focus { + opacity: 1; + } + + .choices[data-type*="select-one"] .choices__button:focus { + box-shadow: 0 0 0 2px #00bcd4; + } + + .choices[data-type*="select-one"] + .choices__item[data-value=""] + .choices__button { + display: none; + } + + .choices[data-type*="select-one"]::after { + content: ""; + height: 0; + width: 0; + border-style: solid; + border-color: hsl(var(--color-text-muted)) transparent transparent; + border-width: 5px; + position: absolute; + right: 11.5px; + top: 50%; + margin-top: -2.5px; + pointer-events: none; + } + + .choices[data-type*="select-one"].is-open::after { + border-color: transparent transparent hsl(var(--color-text-muted)); + margin-top: -7.5px; + } + + .choices[data-type*="select-one"][dir="rtl"]::after { + left: 11.5px; + right: auto; + } + + .choices[data-type*="select-one"][dir="rtl"] .choices__button { + right: auto; + left: 0; + margin-left: 25px; + margin-right: 0; + } + + .choices[data-type*="select-multiple"] .choices__inner, + .choices[data-type*="text"] .choices__inner { + cursor: text; + } + + .choices[data-type*="select-multiple"] .choices__button, + .choices[data-type*="text"] .choices__button { + position: relative; + display: inline-block; + margin-left: 8px; + padding-left: 16px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2300574B'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z'/%3E%3C/svg%3E"); + background-size: 16px; + width: 8px; + line-height: 1; + opacity: 0.75; + border-radius: 0; + } + + .choices[data-type*="select-multiple"] .choices__button:hover, + .choices[data-type*="select-multiple"] .choices__button:focus, + .choices[data-type*="text"] .choices__button:hover, + .choices[data-type*="text"] .choices__button:focus { + opacity: 1; + } + + .choices__inner { + @apply px-3 py-2 rounded-lg border-contrast bg-elevated border-3 transition; + + box-shadow: 2px 2px 0 hsl(var(--color-border-contrast)); + display: inline-block; + vertical-align: top; + width: 100%; + font-size: 16px; + min-height: 42px; + overflow: hidden; + } + + .is-focused .choices__inner, + .is-open .choices__inner { + @apply ring-accent; + } + + .is-open .choices__inner { + @apply rounded-b-none; + } + + .is-flipped.is-open .choices__inner { + @apply rounded-t-none rounded-b-lg border-b-3; + } + + .choices__list { + margin: 0; + padding-left: 0; + list-style: none; + } + + .choices__list--single { + @apply inline-block w-full pr-4; + } + + [dir="rtl"] .choices__list--single { + padding-right: 4px; + padding-left: 16px; + } + + .choices__list--single .choices__item { + width: 100%; + } + + .choices__list--multiple { + @apply inline-flex gap-2 mr-2 items-center; + } + + .choices__list--multiple .choices__item { + @apply inline-block font-semibold px-1 py-0.5 text-sm align-middle rounded text-accent-hover bg-base border-accent-base ring-2 ring-accent-base; + + word-break: break-all; + box-sizing: border-box; + } + + .choices__list--multiple .choices__item[data-deletable] { + padding-right: 5px; + } + + [dir="rtl"] .choices__list--multiple .choices__item { + margin-right: 0; + margin-left: 3.75px; + } + + .choices__list--multiple .choices__item.is-highlighted { + @apply bg-subtle; + } + + .is-disabled .choices__list--multiple .choices__item { + background-color: #aaa; + border: 1px solid #919191; + } + + .choices__list--dropdown { + @apply z-50 border-2 shadow-lg border-contrast; + + display: none; + position: absolute; + width: 100%; + background-color: hsl(var(--color-background-elevated)); + top: 100%; + margin-top: -1px; + overflow: hidden; + word-break: break-all; + } + + .choices__list--dropdown.is-active { + display: block; + } + + .is-open .choices__list--dropdown { + @apply border-t-0 rounded-b-lg; + } + + .is-flipped .choices__list--dropdown { + @apply border-b-0 rounded-t-lg rounded-b-none border-t-3; + + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: -1px; + } + + .choices__list--dropdown .choices__list { + position: relative; + max-height: 300px; + overflow: auto; + -webkit-overflow-scrolling: touch; + will-change: scroll-position; + } + + .choices__list--dropdown .choices__item { + @apply break-normal; + + position: relative; + padding: 10px; + font-size: 14px; + } + + [dir="rtl"] .choices__list--dropdown .choices__item { + text-align: right; + } + + @media (width >= 640px) { + .choices__list--dropdown .choices__item--selectable { + padding-right: 100px; + } + + .choices__list--dropdown .choices__item--selectable::after { + content: attr(data-select-text); + font-size: 12px; + opacity: 0; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + } + + [dir="rtl"] .choices__list--dropdown .choices__item--selectable { + text-align: right; + padding-left: 100px; + padding-right: 10px; + } + + [dir="rtl"] .choices__list--dropdown .choices__item--selectable::after { + right: auto; + left: 10px; + } + } + + .choices__list--dropdown .choices__item--selectable.is-highlighted { + background-color: hsl(var(--color-background-highlight)); + } + + .choices__list--dropdown .choices__item--selectable.is-highlighted::after { + opacity: 0.5; + } + + .choices__item { + cursor: default; + } + + .choices__item--selectable { + cursor: pointer; + } + + .choices__item--disabled { + cursor: not-allowed; + user-select: none; + opacity: 0.5; + } + + .choices__heading { + font-weight: 600; + font-size: 12px; + padding: 10px; + border-bottom: 1px solid #f7f7f7; + color: gray; + } + + .choices__button { + text-indent: -9999px; + appearance: none; + border: 0; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; + } + + .choices__input { + @apply align-middle bg-elevated; + + display: inline-block; + font-size: 14px; + border: 0; + border-radius: 0; + max-width: 100%; + width: 1px; + padding: 0; + } + + .choices__input:focus { + @apply outline-none; + + box-shadow: none; + } + + [dir="rtl"] .choices__input { + padding-right: 2px; + padding-left: 0; + } + + .choices__placeholder { + opacity: 0.5; + } + + .choices__description { + @apply text-xs block text-skin-muted break-normal; + } +} + +/* ===== End of Choices ====== */ diff --git a/resources/styles/_modules/colorRadioBtn.css b/resources/styles/_modules/colorRadioBtn.css new file mode 100644 index 00000000..a6581249 --- /dev/null +++ b/resources/styles/_modules/colorRadioBtn.css @@ -0,0 +1,27 @@ +@layer components { + .color-radio-btn { + @apply absolute opacity-0; + + &:focus + label { + @apply ring-accent; + } + + &:checked { + @apply ring-2 ring-contrast; + + & + label { + @apply flex items-center justify-center text-2xl text-accent-contrast bg-accent-base; + + &::before { + content: "✓"; + } + } + } + + & + label { + @apply inline-block w-16 h-16 text-sm font-semibold rounded-full cursor-pointer border-contrast bg-accent-base text-accent-contrast border-3; + + color: hsl(var(--color-text-muted)); + } + } +} diff --git a/resources/styles/_modules/colors.css b/resources/styles/_modules/colors.css new file mode 100644 index 00000000..d59e79ba --- /dev/null +++ b/resources/styles/_modules/colors.css @@ -0,0 +1,26 @@ +@layer base { + :root { + --color-accent-base: 174 100% 29%; + --color-accent-hover: 172 100% 17%; + --color-accent-muted: 131 100% 12%; + --color-accent-contrast: 0 0% 100%; + --color-heading-foreground: 172 100% 17%; + --color-heading-background: 111 64% 94%; + --color-background-elevated: 0 0% 100%; + --color-background-base: 173 44% 96%; + --color-background-navigation: 172 100% 17%; + --color-background-navigation-active: 131 100% 12%; + --color-background-header: 172 100% 17%; + --color-background-highlight: 111 64% 94%; + --color-background-backdrop: 0 0% 50%; + --color-border-subtle: 111 42% 86%; + --color-border-contrast: 0 0% 0%; + --color-border-navigation: 131 100% 12%; + --color-text-base: 158 8% 3%; + --color-text-muted: 172 8% 38%; + } + + body { + color: hsl(var(--color-text-base)); + } +} diff --git a/resources/styles/_modules/custom.css b/resources/styles/_modules/custom.css new file mode 100644 index 00000000..e327b2ca --- /dev/null +++ b/resources/styles/_modules/custom.css @@ -0,0 +1,105 @@ +@layer base { + html { + scroll-behavior: smooth; + } + + .form-helper { + @apply text-skin-muted; + } + + select { + box-shadow: 2px 2px 0 hsl(var(--color-border-contrast)); + } +} + +@layer components { + .post-content { + & a { + @apply text-sm font-semibold text-accent-base hover:text-accent-hover; + } + } + + .ring-accent { + @apply outline-none ring-2 ring-offset-2 ring-accent-base; + + /* FIXME: why doesn't ring-accent-base work? */ + --tw-ring-opacity: 1; + --tw-ring-color: hsl(var(--color-accent-base) / var(--tw-ring-opacity)); + --tw-ring-offset-color: hsl(var(--color-background-base)); + } + + .rounded-conditional-b-xl { + border-bottom-right-radius: max( + 0px, + min(0.75rem, calc((100vw - 0.75rem - 100%) * 9999)) + ); + border-bottom-left-radius: max( + 0px, + min(0.75rem, calc((100vw - 0.75rem - 100%) * 9999)) + ); + } + + .rounded-conditional-2xl { + border-radius: max(0px, min(1rem, calc((100vw - 1rem - 100%) * 9999))); + } + + .rounded-conditional-full { + border-radius: max(0px, min(9999px, calc((100vw - 1rem - 100%) * 9999))); + } + + .backdrop-gradient { + background-image: linear-gradient( + 180deg, + hsl(0deg 0% 35.29% / 0%) 0%, + hsl(0deg 0% 34.53% / 3.44%) 16.36%, + hsl(0deg 0% 32.42% / 12.5%) 33.34%, + hsl(0deg 0% 29.18% / 25.3%) 50.1%, + hsl(0deg 0% 24.96% / 40%) 65.75%, + hsl(0deg 0% 19.85% / 54.7%) 79.43%, + hsl(0deg 0% 13.95% / 67.5%) 90.28%, + hsl(0deg 0% 7.32% / 76.6%) 97.43%, + hsl(0deg 0% 0% / 80%) 100% + ); + } + + .backdrop-gradient-accent { + /* stylelint-disable-next-line declaration-property-value-no-unknown */ + background-image: linear-gradient( + 180deg, + theme(colors.background.base / 0.4) 0%, + theme(colors.background.base / 0.6) 65.75%, + theme(colors.background.base / 1) 90.28%, + theme(colors.background.base / 1) 97.43%, + theme(colors.background.base / 1) 100% + ); + } + + .bg-stripes-default { + background-image: repeating-linear-gradient( + -45deg, + #f3f4f6, + #f3f4f6 10px, + #e5e7eb 10px, + #e5e7eb 20px + ); + } + + .bg-stripes-warning { + background-image: repeating-linear-gradient( + -45deg, + #fde047, + #fde047 10px, + #facc15 10px, + #facc15 20px + ); + } + + .divide-fieldset-y > :not([hidden], legend) ~ :not([hidden], legend) { + @apply pt-4; + + --tw-divide-y-reverse: 0; + + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } +} diff --git a/resources/styles/_modules/dropdown.css b/resources/styles/_modules/dropdown.css new file mode 100644 index 00000000..e501d4e4 --- /dev/null +++ b/resources/styles/_modules/dropdown.css @@ -0,0 +1,9 @@ +@layer base { + [data-dropdown="menu"] { + @apply absolute z-50; + } + + [data-dropdown="menu"]:not([data-show]) { + @apply hidden; + } +} diff --git a/resources/styles/_modules/fonts.css b/resources/styles/_modules/fonts.css new file mode 100644 index 00000000..f2d9aa00 --- /dev/null +++ b/resources/styles/_modules/fonts.css @@ -0,0 +1,46 @@ +@layer base { + /* kumbh-sans-regular */ + @font-face { + font-family: "Kumbh Sans"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("/assets/fonts/kumbh-sans-regular.woff2") format("woff2"); + } + + /* kumbh-sans-700 */ + @font-face { + font-family: "Kumbh Sans"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("/assets/fonts/kumbh-sans-700.woff2") format("woff2"); + } + + /* inter-regular */ + @font-face { + font-family: Inter; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("/assets/fonts/inter-regular.woff2") format("woff2"); + } + + /* inter-600 */ + @font-face { + font-family: Inter; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("/assets/fonts/inter-600.woff2") format("woff2"); + } + + /* noto-sans-mono-regular */ + @font-face { + font-family: "Noto Sans Mono"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("/assets/fonts/noto-sans-mono-regular.woff2") format("woff2"); + } +} diff --git a/app/Resources/styles/formInputTabs.css b/resources/styles/_modules/formInputTabs.css similarity index 78% rename from app/Resources/styles/formInputTabs.css rename to resources/styles/_modules/formInputTabs.css index 011d39a9..4c5f21e5 100644 --- a/app/Resources/styles/formInputTabs.css +++ b/resources/styles/_modules/formInputTabs.css @@ -24,13 +24,18 @@ @apply relative inline-block px-1 py-2 text-xs text-center cursor-pointer opacity-70 hover:opacity-100; } + .form-input-tabs > input:focus + label { + @apply ring-accent; + } + .form-input-tabs > input:checked + label::after { - @apply absolute inset-x-0 bottom-0 w-full mx-auto bg-pine-700; + @apply absolute inset-x-0 bottom-0 w-full mx-auto bg-accent-base; + content: ""; height: 0.2rem; } .form-input-tabs > input:checked + label { - @apply font-semibold opacity-100 text-pine-700; + @apply font-semibold opacity-100 text-accent-base; } } diff --git a/resources/styles/_modules/inputRange.css b/resources/styles/_modules/inputRange.css new file mode 100644 index 00000000..b474963a --- /dev/null +++ b/resources/styles/_modules/inputRange.css @@ -0,0 +1,99 @@ +.wrap { + display: flex; + align-items: center; + position: relative; + width: 12.5em; + height: 5.25em; + font: + 1em/1 arial, + sans-serif; +} + +[type="range"] { + flex: 1; + margin: 0; + padding: 0; + min-height: 1.5em; + background: transparent; + font: inherit; +} + +[type="range"], +[type="range"]::-webkit-slider-thumb { + appearance: none; +} + +[type="range"]::-webkit-slider-runnable-track { + box-sizing: border-box; + border: none; + width: 12.5em; + height: 0.25em; + background: #ccc; +} + +[type="range"]::-moz-range-track { + box-sizing: border-box; + border: none; + width: 12.5em; + height: 0.25em; + background: #ccc; +} + +[type="range"]::-ms-track { + box-sizing: border-box; + border: none; + width: 12.5em; + height: 0.25em; + background: #ccc; +} + +[type="range"]::-webkit-slider-thumb { + margin-top: -0.625em; + box-sizing: border-box; + border: none; + width: 1.5em; + height: 1.5em; + border-radius: 50%; + background: #f90; +} + +[type="range"]::-moz-range-thumb { + box-sizing: border-box; + border: none; + width: 1.5em; + height: 1.5em; + border-radius: 50%; + background: #f90; +} + +[type="range"]::-ms-thumb { + margin-top: 0; + box-sizing: border-box; + border: none; + width: 1.5em; + height: 1.5em; + border-radius: 50%; + background: #f90; +} + +[type="range"]::-ms-tooltip { + display: none; +} + +[type="range"] ~ output { + display: none; +} + +.js [type="range"] ~ output { + display: block; + position: absolute; + left: 0.75em; + top: 0; + padding: 0.25em 0.5em; + border-radius: 3px; + transform: translate( + calc((var(--val) - var(--min)) / (var(--max) - var(--min)) * 11em - 50%) + ); + background: #95a; + color: #eee; +} diff --git a/resources/styles/_modules/radioBtn.css b/resources/styles/_modules/radioBtn.css new file mode 100644 index 00000000..e892ee0d --- /dev/null +++ b/resources/styles/_modules/radioBtn.css @@ -0,0 +1,33 @@ +@layer components { + .form-radio-btn { + @apply absolute right-4 top-4 border-contrast border-3 text-accent-base transition; + + &:focus { + @apply ring-accent; + } + + &:checked { + & + label { + @apply text-accent-hover bg-base border-accent-base shadow-none; + } + + & + label .form-radio-btn-description { + @apply text-accent-base; + } + } + + & + label { + @apply h-full w-full inline-flex flex-col items-start py-3 px-4 text-sm font-bold rounded-lg cursor-pointer border-contrast bg-elevated border-3 transition-all; + + box-shadow: 2px 2px 0 hsl(var(--color-border-contrast)); + } + + & + label span { + @apply pr-8; + } + + & + label .form-radio-btn-description { + @apply font-normal text-xs text-skin-muted text-balance; + } + } +} diff --git a/app/Resources/styles/radioToggler.css b/resources/styles/_modules/radioToggler.css similarity index 100% rename from app/Resources/styles/radioToggler.css rename to resources/styles/_modules/radioToggler.css diff --git a/resources/styles/_modules/readMore.css b/resources/styles/_modules/readMore.css new file mode 100644 index 00000000..38f40e02 --- /dev/null +++ b/resources/styles/_modules/readMore.css @@ -0,0 +1,56 @@ +/* +Read more component (basic unstyled component) +-- see https://codepen.io/yassinedoghri/pen/QWpwoxp for more info and possible caveats +*/ + +@layer components { + .read-more { + @apply flex flex-col items-start; + + /* You can update this variable directly in the html with the style attribute: style="--line-clamp: 3" */ + --line-clamp: 3; + } + + .read-more__text { + @apply overflow-hidden; + + display: -webkit-box; + -webkit-line-clamp: var(--line-clamp); + -webkit-box-orient: vertical; + } + + .read-more__checkbox { + @apply absolute overflow-hidden whitespace-nowrap; + + clip-path: inset(50%); + height: 1px; + width: 1px; + } + + .read-more__checkbox ~ .read-more__label { + @apply text-xs font-semibold underline cursor-pointer; + } + + /* Don't forget focus and hover styles for accessibility! */ + .read-more__checkbox:focus ~ .read-more__label { + @apply ring-accent; + } + + .read-more__checkbox:hover ~ .read-more__label { + @apply no-underline; + } + + .read-more__checkbox ~ .read-more__label::before { + content: attr(data-read-more); + } + + .read-more__checkbox:checked ~ .read-more__label::before { + content: attr(data-read-less); + } + + .read-more__checkbox:checked ~ .read-more__text { + --line-clamp: none; + + -webkit-line-clamp: var(--line-clamp); + } +} diff --git a/resources/styles/_modules/seeMore.css b/resources/styles/_modules/seeMore.css new file mode 100644 index 00000000..6a191f57 --- /dev/null +++ b/resources/styles/_modules/seeMore.css @@ -0,0 +1,58 @@ +@layer components { + .see-more { + @apply flex flex-col items-start; + } + + .see-more__content { + @apply relative overflow-hidden; + + height: var(--content-height); + } + + .see-more_content-fade { + @apply absolute bottom-0 left-0 w-full h-full pointer-events-none; + + background-image: linear-gradient( + to bottom, + transparent 70%, + hsl(var(--color-background-header)) + ); + } + + .see-more__checkbox { + @apply absolute overflow-hidden whitespace-nowrap; + + clip-path: inset(50%); + height: 1px; + width: 1px; + } + + .see-more__checkbox ~ .see-more__label { + @apply text-xs font-semibold underline cursor-pointer; + } + + /* Don't forget focus and hover styles for accessibility! */ + .see-more__checkbox:focus ~ .see-more__label { + @apply ring-accent; + } + + .see-more__checkbox:hover ~ .see-more__label { + @apply no-underline; + } + + .see-more__checkbox ~ .see-more__label::before { + content: attr(data-see-more); + } + + .see-more__checkbox:checked ~ .see-more__label::before { + content: attr(data-see-less); + } + + .see-more__checkbox:checked ~ .see-more__content { + @apply h-auto; + } + + .see-more__checkbox:checked ~ .see-more__content .see-more_content-fade { + @apply bg-none; + } +} diff --git a/resources/styles/_modules/stickyHeader.css b/resources/styles/_modules/stickyHeader.css new file mode 100644 index 00000000..d58f604c --- /dev/null +++ b/resources/styles/_modules/stickyHeader.css @@ -0,0 +1,24 @@ +:root { + --sticky-header-outer-height: 180px; + --sticky-header-inner-height: 84px; + --sticky-header-height-difference: calc( + var(--sticky-header-outer-height) - var(--sticky-header-inner-height) + ); +} + +/* Sticky header */ +.sticky-header-outer { + /* Make it stick */ + height: var(--sticky-header-outer-height); + position: sticky; + top: calc( + var(--sticky-header-height-difference) * -1 + ); /* Multiply by -1 to get a negative value */ +} + +.sticky-header-inner { + /* Make it stick */ + height: var(--sticky-header-inner-height); + position: sticky; + top: 0; +} diff --git a/resources/styles/_modules/switch.css b/resources/styles/_modules/switch.css new file mode 100644 index 00000000..3065dc40 --- /dev/null +++ b/resources/styles/_modules/switch.css @@ -0,0 +1,67 @@ +@layer components { + .form-switch { + @apply absolute w-0 h-0 opacity-0; + + &:checked + .form-switch-slider { + @apply bg-accent-base; + } + + &:focus + .form-switch-slider { + @apply ring-accent; + } + + &:checked + .form-switch-slider::before { + @apply transform translate-x-6; + } + + &:checked + .form-switch-slider::after { + @apply transform translate-x-0 left-1.5; + + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='m10 15.172 9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z'/%3E%3C/svg%3E%0A"); + } + + &:checked + .form-switch-slider.form-switch-slider--small::before { + @apply translate-x-6; + } + + &:checked + .form-switch-slider.form-switch-slider--small::after { + @apply left-1; + } + } + + .form-switch-slider { + @apply relative inset-0 flex-shrink-0 h-8 transition duration-200 rounded-full cursor-pointer w-14 bg-highlight border-contrast border-3; + + &.form-switch-slider--small { + @apply w-12 h-6; + + &::before { + @apply w-4 h-4; + } + + &::after { + @apply translate-x-5; + + left: 0; + top: -1px; + } + } + + &::before { + @apply absolute z-10 w-6 h-6 transition duration-200 rounded-full shadow bg-elevated ring-1 ring-black ring-opacity-5; + + content: ""; + left: 1px; + bottom: 1px; + } + + &::after { + @apply absolute w-4 h-4 transition duration-150 transform top-1; + + --tw-translate-x: 1.125rem; + + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='m12 10.586 4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z'/%3E%3C/svg%3E%0A"); + left: 10px; + } + } +} diff --git a/app/Resources/styles/tailwind.css b/resources/styles/_modules/tailwind.css similarity index 96% rename from app/Resources/styles/tailwind.css rename to resources/styles/_modules/tailwind.css index 7f393742..b5c61c95 100644 --- a/app/Resources/styles/tailwind.css +++ b/resources/styles/_modules/tailwind.css @@ -1,5 +1,3 @@ @tailwind base; - @tailwind components; - @tailwind utilities; diff --git a/resources/styles/admin.css b/resources/styles/admin.css new file mode 100644 index 00000000..bb90fa4b --- /dev/null +++ b/resources/styles/admin.css @@ -0,0 +1,17 @@ +@import url("./_modules/tailwind.css"); +@import url("./_modules/custom.css"); +@import url("./_modules/fonts.css"); +@import url("./_modules/colors.css"); +@import url("./_modules/breadcrumb.css"); +@import url("./_modules/dropdown.css"); +@import url("./_modules/choices.css"); +@import url("./_modules/radioBtn.css"); +@import url("./_modules/colorRadioBtn.css"); +@import url("./_modules/switch.css"); +@import url("./_modules/radioToggler.css"); +@import url("./_modules/formInputTabs.css"); +@import url("./_modules/stickyHeader.css"); +@import url("./_modules/readMore.css"); +@import url("./_modules/seeMore.css"); + +@config '../../tailwind.admin.config.js'; diff --git a/resources/styles/install.css b/resources/styles/install.css new file mode 100644 index 00000000..e14d0dc0 --- /dev/null +++ b/resources/styles/install.css @@ -0,0 +1,17 @@ +@import url("./_modules/tailwind.css"); +@import url("./_modules/custom.css"); +@import url("./_modules/fonts.css"); +@import url("./_modules/colors.css"); +@import url("./_modules/breadcrumb.css"); +@import url("./_modules/dropdown.css"); +@import url("./_modules/choices.css"); +@import url("./_modules/radioBtn.css"); +@import url("./_modules/colorRadioBtn.css"); +@import url("./_modules/switch.css"); +@import url("./_modules/radioToggler.css"); +@import url("./_modules/formInputTabs.css"); +@import url("./_modules/stickyHeader.css"); +@import url("./_modules/readMore.css"); +@import url("./_modules/seeMore.css"); + +@config '../../tailwind.install.config.js'; diff --git a/resources/styles/site.css b/resources/styles/site.css new file mode 100644 index 00000000..c5e54f99 --- /dev/null +++ b/resources/styles/site.css @@ -0,0 +1,17 @@ +@import url("./_modules/tailwind.css"); +@import url("./_modules/custom.css"); +@import url("./_modules/fonts.css"); +@import url("./_modules/colors.css"); +@import url("./_modules/breadcrumb.css"); +@import url("./_modules/dropdown.css"); +@import url("./_modules/choices.css"); +@import url("./_modules/radioBtn.css"); +@import url("./_modules/colorRadioBtn.css"); +@import url("./_modules/switch.css"); +@import url("./_modules/radioToggler.css"); +@import url("./_modules/formInputTabs.css"); +@import url("./_modules/stickyHeader.css"); +@import url("./_modules/readMore.css"); +@import url("./_modules/seeMore.css"); + +@config '../../tailwind.config.js'; diff --git a/scripts/bundle-prepare.sh b/scripts/bundle-prepare.sh index 883110a8..4d011586 100644 --- a/scripts/bundle-prepare.sh +++ b/scripts/bundle-prepare.sh @@ -1,8 +1,9 @@ -#!/bin/bash +#!/bin/sh +set -e # install only production dependencies using the --no-dev option composer install --no-dev --prefer-dist --no-ansi --no-interaction --no-progress --ignore-platform-reqs # build all production static assets (css, js, images, icons, fonts, etc.) -npm run build -npm run build:static +pnpm run build +pnpm run build:static diff --git a/scripts/bundle.sh b/scripts/bundle.sh index d3e4893f..2d049601 100644 --- a/scripts/bundle.sh +++ b/scripts/bundle.sh @@ -1,26 +1,21 @@ -#!/bin/bash +#!/bin/sh +set -e VERSION=$1 -COMPOSER_VERSION=$(echo "$VERSION" | perl -pe 's/(?<=[alpha|beta])\.//g') +COMPOSER_VERSION=$(echo "$VERSION" | sed -r 's/(alpha|beta|next)./\1/g') +COMPOSER_VERSION=$(echo "$COMPOSER_VERSION" | sed -r 's/next[0-9]+/dev/g') # replace composer.json version using jq -apt-get install jq -y echo "$( jq '.version = "'$COMPOSER_VERSION'"' composer.json )" > composer.json # replace CP_VERSION constant in app/config/constants sed -i "s/^defined('CP_VERSION').*/defined('CP_VERSION') || define('CP_VERSION', '$VERSION');/" ./app/Config/Constants.php -# install wget to download archives -apt-get install wget - # download GeoLite2-City archive and extract it to writable/uploads wget -c "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=$MAXMIND_LICENCE_KEY&suffix=tar.gz" -O - | tar -xz -C ./writable/uploads/ # rename extracted archives' folders mv ./writable/uploads/GeoLite2-City* ./writable/uploads/GeoLite2-City -# install rsync for file transfers -apt-get install rsync -y - -# create castopo-host folder bundle: uses .rsync-filter (-F) file to copy only needed files -rsync -aF --progress . ./castopod-host +# create castopod folder bundle: uses .rsync-filter (-F) file to copy only needed files +rsync -aF . ./castopod diff --git a/scripts/lint-commit-msg.sh b/scripts/lint-commit-msg.sh index 00fb1e26..173d5821 100755 --- a/scripts/lint-commit-msg.sh +++ b/scripts/lint-commit-msg.sh @@ -1,18 +1,19 @@ -#!/bin/bash +#!/bin/sh +set -e # see https://github.com/conventional-changelog/commitlint/issues/885 if [ "${CI_COMMIT_BEFORE_SHA}" = "0000000000000000000000000000000000000000" ]; then echo "commitlint from HEAD^" - npx commitlint --from=HEAD^ + pnpm exec commitlint --from=HEAD^ else echo "commitlint from ${CI_COMMIT_BEFORE_SHA}" br=`git branch -r --contains ${CI_COMMIT_BEFORE_SHA}` if [ ! -n $br ]; then - npx commitlint --from=HEAD^ + pnpm exec commitlint --from=HEAD^ else - npx commitlint --from="${CI_COMMIT_BEFORE_SHA}" + pnpm exec commitlint --from="${CI_COMMIT_BEFORE_SHA}" fi fi diff --git a/scripts/package.sh b/scripts/package.sh index adefe625..c6269f5c 100644 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -1,9 +1,8 @@ -#!/bin/bash +#!/bin/sh +set -e VERSION=$1 -apt-get install zip -y - # create zip and tar.gz packages for release upload -zip -r castopod-host-$VERSION.zip castopod-host -tar -zcvf castopod-host-$VERSION.tar.gz castopod-host +zip -r castopod-$VERSION.zip castopod +tar -zcvf castopod-$VERSION.tar.gz castopod diff --git a/spark b/spark index f62aeddb..aef372bc 100644 --- a/spark +++ b/spark @@ -1,18 +1,71 @@ #!/usr/bin/env php + * + * For the full copyright and license information, please view the LICENSE file that was distributed with this source + * code. + */ + /* * -------------------------------------------------------------------- - * CodeIgniter command-line tools + * CODEIGNITER COMMAND-LINE TOOLS * -------------------------------------------------------------------- * The main entry point into the CLI system and allows you to run * commands and perform maintenance on your application. - * - * Because CodeIgniter can handle CLI requests as just another web request - * this class mainly acts as a passthru to the framework itself. */ -define('SPARKED', true); +/* + *--------------------------------------------------------------- + * CHECK SERVER API + *--------------------------------------------------------------- + */ + +// Refuse to run when called from php-cgi +if (str_starts_with(PHP_SAPI, 'cgi')) { + exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n"); +} + +/* + *--------------------------------------------------------------- + * CHECK PHP VERSION + *--------------------------------------------------------------- + */ + +$minPhpVersion = '8.5'; // If you update this, don't forget to update `public/index.php`. +if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { + $message = sprintf( + 'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s', + $minPhpVersion, + PHP_VERSION, + ); + + exit($message); +} + +// We want errors to be shown when using it from the CLI. +error_reporting(E_ALL); +ini_set('display_errors', '1'); + +/* + *--------------------------------------------------------------- + * SET THE CURRENT DIRECTORY + *--------------------------------------------------------------- + */ + +// Path to the front controller +define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); + +// Ensure the current directory is pointing to the front controller's directory +chdir(FCPATH); /* *--------------------------------------------------------------- @@ -23,47 +76,14 @@ define('SPARKED', true); * and fires up an environment-specific bootstrapping. */ -// Refuse to run when called from php-cgi -if (strpos(PHP_SAPI, 'cgi') === 0) -{ - die("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n"); -} - -// Path to the front controller -define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); - -// Load our paths config file -$pathsConfig = 'app/Config/Paths.php'; +// LOAD OUR PATHS CONFIG FILE +// This is the line that might need to be changed, depending on your folder structure. +require FCPATH . '../app/Config/Paths.php'; // ^^^ Change this line if you move your application folder -require realpath($pathsConfig) ?: $pathsConfig; -$paths = new Config\Paths(); +$paths = new Paths(); -// Ensure the current directory is pointing to the front controller's directory -chdir(FCPATH); +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; -$bootstrap = rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; -$app = require realpath($bootstrap) ?: $bootstrap; - -// Grab our Console -$console = new CodeIgniter\CLI\Console($app); - -// We want errors to be shown when using it from the CLI. -error_reporting(-1); -ini_set('display_errors', '1'); - -// Show basic information before we do anything else. -if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) -{ - unset($_SERVER['argv'][$suppress]); // @codeCoverageIgnore - $suppress = true; -} - -$console->showHeader($suppress); - -// fire off the command in the main framework. -$response = $console->run(); -if ($response->getStatusCode() >= 300) -{ - exit($response->getStatusCode()); -} +exit(Boot::bootSpark($paths)); diff --git a/tailwind.admin.config.js b/tailwind.admin.config.js new file mode 100644 index 00000000..f6d4fea4 --- /dev/null +++ b/tailwind.admin.config.js @@ -0,0 +1,171 @@ +import defaultTheme from "tailwindcss/defaultTheme"; +import tailwindForms from "@tailwindcss/forms"; +import tailwindTypography from "@tailwindcss/typography"; + +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./app/Views/**/*.php", + "./themes/cp_admin/**/*.php", + "./themes/cp_auth/**/*.php", + "./app/Helpers/*.php", + "./resources/**/*.ts", + ], + theme: { + extend: { + content: { + chevronRightIcon: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' viewBox='0 0 24 24'%3E%3Cpath d='M13.17 12 8.22 7.05l1.42-1.41L16 12l-6.36 6.36-1.42-1.41L13.17 12Z'/%3E%3C/svg%3E%0A\")", + prohibitedIcon: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' viewBox='0 0 24 24'%3E%3Cpath d='M7.0943 5.68009L18.3199 16.9057C19.3736 15.5506 20 13.8491 20 12C20 7.58172 16.4183 4 12 4C10.1509 4 8.44939 4.62644 7.0943 5.68009ZM16.9057 18.3199L5.68009 7.0943C4.62644 8.44939 4 10.1509 4 12C4 16.4183 7.58172 20 12 20C13.8491 20 15.5506 19.3736 16.9057 18.3199ZM4.92893 4.92893C6.73748 3.12038 9.23885 2 12 2C17.5228 2 22 6.47715 22 12C22 14.7611 20.8796 17.2625 19.0711 19.0711C17.2625 20.8796 14.7611 22 12 22C6.47715 22 2 17.5228 2 12C2 9.23885 3.12038 6.73748 4.92893 4.92893Z'/%3E%3C/svg%3E%0A\")", + }, + fontFamily: { + sans: ["Inter", ...defaultTheme.fontFamily.sans], + display: ["Kumbh Sans", ...defaultTheme.fontFamily.sans], + mono: ["Noto Sans Mono", ...defaultTheme.fontFamily.mono], + }, + textDecorationThickness: { + 3: "3px", + }, + textColor: { + skin: { + base: "hsl(var(--color-text-base) / )", + muted: "hsl(var(--color-text-muted) / )", + }, + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + muted: "hsl(var(--color-accent-muted) / )", + contrast: "hsl(var(--color-accent-contrast) / )", + }, + }, + backgroundColor: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + subtle: "hsl(var(--color-border-subtle) / )", + navigation: "hsl(var(--color-background-navigation) / )", + "navigation-active": + "hsl(var(--color-background-navigation-active) / )", + backdrop: "hsl(var(--color-background-backdrop) / )", + header: "hsl(var(--color-background-header) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + highlight: "hsl(var(--color-background-highlight) / )", + }, + borderColor: { + subtle: "hsl(var(--color-border-subtle) / )", + contrast: "hsl(var(--color-border-contrast) / )", + navigation: "hsl(var(--color-border-navigation) / )", + "navigation-bg": + "hsl(var(--color-background-navigation) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, + }, + ringColor: { + contrast: "hsl(var(--color-border-contrast) / )", + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, + }, + colors: { + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + header: "hsl(var(--color-background-header) / )", + base: "hsl(var(--color-background-base) / )", + }, + heading: { + foreground: "hsl(var(--color-heading-foreground) / )", + background: "hsl(var(--color-heading-background) / )", + }, + pine: { + 50: "#F2FAF9", + 100: "#E7F9E4", + 200: "#bfe4e1", + 300: "#99d4cf", + 400: "#4db4aa", + 500: "#009486", + 600: "#008579", + 700: "#006D60", + 800: "#00564A", + 900: "#003D0B", + }, + }, + gridTemplateColumns: { + admin: "300px calc(100% - 300px)", + podcast: "1fr minmax(auto, 960px) 1fr", + podcastMain: "1fr minmax(200px, 300px)", + cards: "repeat(auto-fill, minmax(14rem, 1fr))", + latestEpisodes: "repeat(5, 1fr)", + colorButtons: "repeat(auto-fill, minmax(4rem, 1fr))", + platforms: "repeat(auto-fill, minmax(18rem, 1fr))", + plugins: "repeat(auto-fill, minmax(20rem, 1fr))", + radioGroup: "repeat(auto-fit, minmax(14rem, 1fr))", + }, + gridTemplateRows: { + admin: "40px 1fr", + }, + borderWidth: { + 3: "3px", + }, + ringWidth: { + 3: "3px", + }, + typography: { + DEFAULT: { + css: { + a: { + textDecoration: "underline", + fontWeight: 600, + "&:hover": { + textDecoration: "none", + }, + }, + input: { + margin: 0, + }, + }, + }, + sm: { + css: { + a: { + textDecoration: "underline", + fontWeight: 600, + "&:hover": { + textDecoration: "none", + }, + }, + }, + }, + }, + zIndex: { + 60: 60, + }, + keyframes: { + "slight-pulse": { + "0%": { transform: "scale(1)" }, + "60%": { transform: "scale(0.96)" }, + "75%": { transform: "scale(1.05)" }, + "95%": { transform: "scale(0.98)" }, + "100%": { transform: "scale(1)" }, + }, + }, + animation: { + "single-pulse": "slight-pulse 300ms linear 1", + }, + }, + }, + variants: {}, + plugins: [tailwindForms, tailwindTypography], +}; diff --git a/tailwind.config.js b/tailwind.config.js index 36fd2211..42ba73eb 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,57 +1,159 @@ -/* eslint-disable */ +import defaultTheme from "tailwindcss/defaultTheme"; +import tailwindForms from "@tailwindcss/forms"; +import tailwindTypography from "@tailwindcss/typography"; -module.exports = { - mode: "jit", - purge: [ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ "./app/Views/**/*.php", + "./modules/**/Views/**/*.php", + "./themes/cp_app/**/*.php", "./app/Helpers/*.php", - "./app/Resources/**/*.ts", + "./resources/**/*.ts", ], theme: { extend: { + content: { + chevronRightIcon: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' viewBox='0 0 24 24'%3E%3Cpath d='M13.17 12 8.22 7.05l1.42-1.41L16 12l-6.36 6.36-1.42-1.41L13.17 12Z'/%3E%3C/svg%3E%0A\")", + prohibitedIcon: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' viewBox='0 0 24 24'%3E%3Cpath d='M7.0943 5.68009L18.3199 16.9057C19.3736 15.5506 20 13.8491 20 12C20 7.58172 16.4183 4 12 4C10.1509 4 8.44939 4.62644 7.0943 5.68009ZM16.9057 18.3199L5.68009 7.0943C4.62644 8.44939 4 10.1509 4 12C4 16.4183 7.58172 20 12 20C13.8491 20 15.5506 19.3736 16.9057 18.3199ZM4.92893 4.92893C6.73748 3.12038 9.23885 2 12 2C17.5228 2 22 6.47715 22 12C22 14.7611 20.8796 17.2625 19.0711 19.0711C17.2625 20.8796 14.7611 22 12 22C6.47715 22 2 17.5228 2 12C2 9.23885 3.12038 6.73748 4.92893 4.92893Z'/%3E%3C/svg%3E%0A\")", + }, fontFamily: { - sans: ["Montserrat", "sans-serif"], - display: ["Kumbh Sans", "sans-serif"], - body: ["Montserrat", "sans-serif"], + sans: ["Inter", ...defaultTheme.fontFamily.sans], + display: ["Kumbh Sans", ...defaultTheme.fontFamily.sans], + mono: ["Noto Sans Mono", ...defaultTheme.fontFamily.mono], + }, + textDecorationThickness: { + 3: "3px", + }, + textColor: { + skin: { + base: "hsl(var(--color-text-base) / )", + muted: "hsl(var(--color-text-muted) / )", + }, + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + muted: "hsl(var(--color-accent-muted) / )", + contrast: "hsl(var(--color-accent-contrast) / )", + }, + }, + backgroundColor: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + subtle: "hsl(var(--color-border-subtle) / )", + navigation: "hsl(var(--color-background-navigation) / )", + "navigation-active": + "hsl(var(--color-background-navigation-active) / )", + backdrop: "hsl(var(--color-background-backdrop) / )", + header: "hsl(var(--color-background-header) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + highlight: "hsl(var(--color-background-highlight) / )", + }, + borderColor: { + subtle: "hsl(var(--color-border-subtle) / )", + contrast: "hsl(var(--color-border-contrast) / )", + navigation: "hsl(var(--color-border-navigation) / )", + "navigation-bg": + "hsl(var(--color-background-navigation) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, + }, + ringColor: { + contrast: "hsl(var(--color-border-contrast) / )", + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, }, colors: { + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + header: "hsl(var(--color-background-header) / )", + base: "hsl(var(--color-background-base) / )", + }, + heading: { + foreground: "hsl(var(--color-heading-foreground) / )", + background: "hsl(var(--color-heading-background) / )", + }, pine: { - 50: "#ebf8f8", - 100: "#cff7f3", - 200: "#9df2e4", - 300: "#5ee8d4", - 400: "#1cd7ba", - 500: "#08c09a", - 600: "#07a57d", - 700: "#009486", - 800: "#006D60", - 900: "#00564A", + 50: "#F2FAF9", + 100: "#E7F9E4", + 200: "#bfe4e1", + 300: "#99d4cf", + 400: "#4db4aa", + 500: "#009486", + 600: "#008579", + 700: "#006D60", + 800: "#00564A", + 900: "#003D0B", }, - rose: { - 50: "#fcf9f8", - 100: "#fdeef2", - 200: "#fbcfe4", - 300: "#faa7cd", - 400: "#fb6ea5", - 500: "#fc437c", - 600: "#f24664", - 700: "#dd1f47", - 800: "#b21a39", - 900: "#8e162e", - }, - }, - spacing: { - 112: "28rem", }, gridTemplateColumns: { - podcasts: "repeat(auto-fill, minmax(14rem, 1fr))", + admin: "300px calc(100% - 300px)", + podcast: "1fr minmax(auto, 960px) 1fr", + podcastMain: "1fr minmax(200px, 300px)", + cards: "repeat(auto-fill, minmax(14rem, 1fr))", + latestEpisodes: "repeat(5, 1fr)", + colorButtons: "repeat(auto-fill, minmax(4rem, 1fr))", + platforms: "repeat(auto-fill, minmax(18rem, 1fr))", + plugins: "repeat(auto-fill, minmax(20rem, 1fr))", + radioGroup: "repeat(auto-fit, minmax(14rem, 1fr))", + }, + gridTemplateRows: { + admin: "40px 1fr", + }, + borderWidth: { + 3: "3px", + }, + ringWidth: { + 3: "3px", + }, + typography: { + DEFAULT: { + css: { + a: { + textDecoration: "underline", + fontWeight: 600, + "&:hover": { + textDecoration: "none", + }, + }, + input: { + margin: 0, + }, + }, + }, + sm: { + css: { + a: { + textDecoration: "underline", + fontWeight: 600, + "&:hover": { + textDecoration: "none", + }, + }, + }, + }, + }, + zIndex: { + 60: 60, }, }, }, variants: {}, - plugins: [ - require("@tailwindcss/forms"), - require("@tailwindcss/typography"), - require("@tailwindcss/line-clamp"), - ], + plugins: [tailwindForms, tailwindTypography], }; diff --git a/tailwind.install.config.js b/tailwind.install.config.js new file mode 100644 index 00000000..3313dcee --- /dev/null +++ b/tailwind.install.config.js @@ -0,0 +1,106 @@ +import defaultTheme from "tailwindcss/defaultTheme"; +import tailwindForms from "@tailwindcss/forms"; + +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./app/Views/**/*.php", + "./themes/cp_install/**/*.php", + "./resources/**/*.ts", + ], + theme: { + extend: { + fontFamily: { + sans: ["Inter", ...defaultTheme.fontFamily.sans], + display: ["Kumbh Sans", ...defaultTheme.fontFamily.sans], + mono: ["Noto Sans Mono", ...defaultTheme.fontFamily.mono], + }, + textDecorationThickness: { + 3: "3px", + }, + textColor: { + skin: { + base: "hsl(var(--color-text-base) / )", + muted: "hsl(var(--color-text-muted) / )", + }, + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + muted: "hsl(var(--color-accent-muted) / )", + contrast: "hsl(var(--color-accent-contrast) / )", + }, + }, + backgroundColor: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + subtle: "hsl(var(--color-border-subtle) / )", + navigation: "hsl(var(--color-background-navigation) / )", + "navigation-active": + "hsl(var(--color-background-navigation-active) / )", + backdrop: "hsl(var(--color-background-backdrop) / )", + header: "hsl(var(--color-background-header) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + highlight: "hsl(var(--color-background-highlight) / )", + }, + borderColor: { + subtle: "hsl(var(--color-border-subtle) / )", + contrast: "hsl(var(--color-border-contrast) / )", + navigation: "hsl(var(--color-border-navigation) / )", + "navigation-bg": + "hsl(var(--color-background-navigation) / )", + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, + }, + ringColor: { + contrast: "hsl(var(--color-border-contrast) / )", + background: { + base: "hsl(var(--color-background-base) / )", + elevated: "hsl(var(--color-background-elevated) / )", + }, + }, + colors: { + accent: { + base: "hsl(var(--color-accent-base) / )", + hover: "hsl(var(--color-accent-hover) / )", + }, + background: { + header: "hsl(var(--color-background-header) / )", + base: "hsl(var(--color-background-base) / )", + }, + heading: { + foreground: "hsl(var(--color-heading-foreground) / )", + background: "hsl(var(--color-heading-background) / )", + }, + pine: { + 50: "#F2FAF9", + 100: "#E7F9E4", + 200: "#bfe4e1", + 300: "#99d4cf", + 400: "#4db4aa", + 500: "#009486", + 600: "#008579", + 700: "#006D60", + 800: "#00564A", + 900: "#003D0B", + }, + }, + borderWidth: { + 3: "3px", + }, + ringWidth: { + 3: "3px", + }, + }, + }, + variants: {}, + plugins: [tailwindForms], +}; diff --git a/tests/.htaccess b/tests/.htaccess new file mode 100644 index 00000000..3462048a --- /dev/null +++ b/tests/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + diff --git a/tests/README.md b/tests/README.md index 3452c2d1..d4224da6 100644 --- a/tests/README.md +++ b/tests/README.md @@ -7,58 +7,72 @@ test your application. Those details can be found in the documentation. ## Resources -- [CodeIgniter 4 User Guide on Testing](https://codeigniter4.github.io/userguide/testing/index.html) -- [PHPUnit docs](https://phpunit.readthedocs.io/en/8.5/index.html) +- [CodeIgniter 4 User Guide on Testing](https://codeigniter.com/user_guide/testing/index.html) +- [PHPUnit docs](https://phpunit.de/documentation.html) +- [Any tutorials on Unit testing in CI4?](https://forum.codeigniter.com/showthread.php?tid=81830) ## Requirements It is recommended to use the latest version of PHPUnit. At the time of this -writing we are running version 8.5.13. Support for this has been built into the +writing, we are running version 9.x. Support for this has been built into the **composer.json** file that ships with CodeIgniter and can easily be installed via [Composer](https://getcomposer.org/) if you don't already have it installed globally. - > composer install +```console +> composer install +``` -If running under OS X or Linux, you can create a symbolic link to make running +If running under macOS or Linux, you can create a symbolic link to make running tests a touch nicer. - > ln -s ./vendor/bin/phpunit ./phpunit +```console +> ln -s ./vendor/bin/phpunit ./phpunit +``` -You also need to install [XDebug](https://xdebug.org/index.php) in order for -code coverage to be calculated successfully. +You also need to install [XDebug](https://xdebug.org/docs/install) in order for +code coverage to be calculated successfully. After installing `XDebug`, you must +add `xdebug.mode=coverage` in the **php.ini** file to enable code coverage. ## Setting Up A number of the tests use a running database. In order to set up the database edit the details for the `tests` group in **app/Config/Database.php** or -**phpunit.xml**. Make sure that you provide a database engine that is currently -running on your machine. More details on a test database setup are in the -_Docs>>Testing>>Testing Your Database_ section of the documentation. - -If you want to run the tests without using live database you can exclude -@DatabaseLive group. Or make a copy of **phpunit.dist.xml** - call it -**phpunit.xml** - and comment out the named "database". This will -make the tests run quite a bit faster. +**.env**. Make sure that you provide a database engine that is currently running +on your machine. More details on a test database setup are in the +[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) +section of the documentation. ## Running the tests The entire test suite can be run by simply typing one command-line command from the main directory. - > ./phpunit +```console +> ./phpunit +``` + +If you are using Windows, use the following command. + +```console +> vendor\bin\phpunit +``` You can limit tests to those within a single test directory by specifying the directory name after phpunit. - > ./phpunit app/Models +```console +> ./phpunit app/Models +``` ## Generating Code Coverage To generate coverage information, including HTML reports you can view in your browser, you can use the following command: - > ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m +```console +> ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m +``` This runs all of the tests again collecting information about how many lines, functions, and files are tested. It also reports the percentage of the code that @@ -82,14 +96,12 @@ to exclude database tests, or automatically generate HTML code coverage reports. ## Test Cases Every test needs a _test case_, or class that your tests extend. CodeIgniter 4 -provides a few that you may use directly: +provides one class that you may use directly: -- `CodeIgniter\Test\CIUnitTestCase` - for basic tests with no other service - needs -- `CodeIgniter\Test\DatabaseTestTrait` - for tests that need database access +- `CodeIgniter\Test\CIUnitTestCase` -Most of the time you will want to write your own test cases to hold functions -and services common to your test suites. +Most of the time you will want to write your own test cases that extend +`CIUnitTestCase` to hold functions and services common to your test suites. ## Creating Tests @@ -104,13 +116,9 @@ how. Review the links above and always pay attention to your code coverage. ### Database Tests -Tests can include migrating, seeding, and testing against a mock or -live1 database. Be sure to modify the test case (or create your own) -to point to your seed and migrations and include any additional steps to be run -before tests in the `setUp()` method. - -1 Note: If you are using database tests that require a live database -connection you will need to rename **phpunit.xml.dist** to **phpunit.xml**, -uncomment the database configuration lines and add your connection details. -Prevent **phpunit.xml** from being tracked in your repo by adding it to -**.gitignore**. +Tests can include migrating, seeding, and testing against a mock or live +database. Be sure to modify the test case (or create your own) to point to your +seed and migrations and include any additional steps to be run before tests in +the `setUp()` method. See +[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) +for details. diff --git a/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php b/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php index 243f4682..faf98ca8 100644 --- a/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php +++ b/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Tests\Support\Database\Migrations; use CodeIgniter\Database\Migration; +use Override; class ExampleMigration extends Migration { @@ -13,27 +14,28 @@ class ExampleMigration extends Migration */ protected $DBGroup = 'tests'; + #[Override] public function up(): void { $fields = [ 'name' => [ - 'type' => 'varchar', + 'type' => 'varchar', 'constraint' => 31, ], 'uid' => [ - 'type' => 'varchar', + 'type' => 'varchar', 'constraint' => 31, ], 'class' => [ - 'type' => 'varchar', + 'type' => 'varchar', 'constraint' => 63, ], 'icon' => [ - 'type' => 'varchar', + 'type' => 'varchar', 'constraint' => 31, ], 'summary' => [ - 'type' => 'varchar', + 'type' => 'varchar', 'constraint' => 255, ], 'created_at' => [ @@ -61,6 +63,7 @@ class ExampleMigration extends Migration $this->forge->createTable('factories'); } + #[Override] public function down(): void { $this->forge->dropTable('factories'); diff --git a/tests/_support/Database/Seeds/ExampleSeeder.php b/tests/_support/Database/Seeds/ExampleSeeder.php index e519a913..52a4bed6 100644 --- a/tests/_support/Database/Seeds/ExampleSeeder.php +++ b/tests/_support/Database/Seeds/ExampleSeeder.php @@ -5,31 +5,33 @@ declare(strict_types=1); namespace Tests\Support\Database\Seeds; use CodeIgniter\Database\Seeder; +use Override; class ExampleSeeder extends Seeder { + #[Override] public function run(): void { $factories = [ [ - 'name' => 'Test Factory', - 'uid' => 'test001', - 'class' => 'Factories\Tests\NewFactory', - 'icon' => 'fas fa-puzzle-piece', + 'name' => 'Test Factory', + 'uid' => 'test001', + 'class' => 'Factories\Tests\NewFactory', + 'icon' => 'fas fa-puzzle-piece', 'summary' => 'Longer sample text for testing', ], [ - 'name' => 'Widget Factory', - 'uid' => 'widget', - 'class' => 'Factories\Tests\WidgetPlant', - 'icon' => 'fas fa-puzzle-piece', + 'name' => 'Widget Factory', + 'uid' => 'widget', + 'class' => 'Factories\Tests\WidgetPlant', + 'icon' => 'fas fa-puzzle-piece', 'summary' => 'Create widgets in your factory', ], [ - 'name' => 'Evil Factory', - 'uid' => 'evil-maker', - 'class' => 'Factories\Evil\MyFactory', - 'icon' => 'fas fa-book-dead', + 'name' => 'Evil Factory', + 'uid' => 'evil-maker', + 'class' => 'Factories\Evil\MyFactory', + 'icon' => 'fas fa-book-dead', 'summary' => 'Abandon all hope, ye who enter here', ], ]; diff --git a/tests/_support/Database/Seeds/FakeSinglePodcastApiSeeder.php b/tests/_support/Database/Seeds/FakeSinglePodcastApiSeeder.php new file mode 100644 index 00000000..3fbd17c4 --- /dev/null +++ b/tests/_support/Database/Seeds/FakeSinglePodcastApiSeeder.php @@ -0,0 +1,202 @@ + 3, + 'file_key' => 'podcasts/test/1685531765_84fb3309111ece22ca37.mp3', + 'file_size' => '2737773', + 'file_mimetype' => 'audio/mpeg', + 'file_metadata' => '{"GETID3_VERSION":"2.0.x-202207161647","filesize":2737773,"filepath":"\\/tmp","filename":"php76vXQR","filenamepath":"\\/tmp\\/php76vXQR","avdataoffset":45,"avdataend":2737773,"fileformat":"mp3","audio":{"dataformat":"mp3","channels":2,"sample_rate":48000,"bitrate":128008.9774161874,"channelmode":"stereo","bitrate_mode":"cbr","lossless":false,"encoder_options":"CBR128","compression_ratio":0.08333917800533033,"streams":[{"dataformat":"mp3","channels":2,"sample_rate":48000,"bitrate":128008.9774161874,"channelmode":"stereo","bitrate_mode":"cbr","lossless":false,"encoder_options":"CBR128","compression_ratio":0.08333917800533033}]},"tags":{"id3v2":{"encoder_settings":["Lavf58.29.100"]}},"encoding":"UTF-8","id3v2":{"header":true,"flags":{"unsynch":false,"exthead":false,"experim":false,"isfooter":false},"majorversion":4,"minorversion":0,"headerlength":45,"tag_offset_start":0,"tag_offset_end":45,"encoding":"UTF-8","comments":{"encoder_settings":["Lavf58.29.100"]},"TSSE":[{"frame_name":"TSSE","frame_flags_raw":0,"data":"Lavf58.29.100","datalength":15,"dataoffset":10,"framenamelong":"Software\\/Hardware and settings used for encoding","framenameshort":"encoder_settings","flags":{"TagAlterPreservation":false,"FileAlterPreservation":false,"ReadOnly":false,"GroupingIdentity":false,"compression":false,"Encryption":false,"Unsynchronisation":false,"DataLengthIndicator":false},"encodingid":3,"encoding":"UTF-8"}],"padding":{"start":35,"length":10,"valid":true}},"mime_type":"audio\\/mpeg","mpeg":{"audio":{"raw":{"synch":4094,"version":3,"layer":1,"protection":1,"bitrate":5,"sample_rate":1,"padding":0,"private":0,"channelmode":0,"modeextension":0,"copyright":0,"original":0,"emphasis":0},"version":"1","layer":3,"channelmode":"stereo","channels":2,"sample_rate":48000,"protection":false,"private":false,"modeextension":"","copyright":false,"original":false,"emphasis":"none","padding":false,"bitrate":128008.9774161874,"framelength":384,"bitrate_mode":"cbr","VBR_method":"Xing","xing_flags_raw":15,"xing_flags":{"frames":true,"bytes":true,"toc":true,"vbr_scale":true},"VBR_frames":7129,"VBR_bytes":2737728,"toc":[0,3,5,8,10,13,16,18,20,22,26,28,31,33,36,39,41,43,45,49,51,54,56,59,62,64,66,68,72,74,77,79,82,85,87,89,91,95,97,99,102,105,108,110,112,114,118,120,122,125,128,131,133,135,137,141,143,145,148,150,153,156,158,160,164,166,168,171,173,176,179,181,183,187,189,191,194,196,199,202,204,206,210,212,214,217,219,222,225,227,229,233,235,237,240,242,245,248,250,252],"VBR_scale":0,"VBR_bitrate":128008.9774161874}},"playtime_seconds":171.0720016831475,"tags_html":{"id3v2":{"encoder_settings":["Lavf58.29.100"]}},"bitrate":128008.9774161874,"playtime_string":"2:51"}', + 'type' => 'audio', + 'description' => null, + 'language_code' => 'pl', + 'uploaded_by' => '1', + 'updated_by' => '1', + 'uploaded_at' => '2023-05-31 11:16:05', + 'updated_at' => '2023-05-31 11:16:05', + ]; + } + + /** + * @return array{id: int, file_key: string, file_size: int, file_mimetype: string, file_metadata: string, type: string, description: null, language_code: null, uploaded_by: int, updated_by: int, uploaded_at: string, updated_at: string} + */ + public static function cover(): array + { + return [ + 'id' => 1, + 'file_key' => 'podcasts/Handle/cover.jpg', + 'file_size' => 400000, + 'file_mimetype' => 'image/jpeg', + 'file_metadata' => '{"FILE":{"FileName":"cover.jpg","FileDateTime":1654861723,"FileSize":468541,"FileType":2,"MimeType":"image\/jpeg","SectionsFound":"COMMENT"},"COMPUTED":{"html":"width=\"1400\" height=\"1400\"","Height":1400,"Width":1400,"IsColor":1},"COMMENT":["CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90\n"],"sizes":{"tiny":{"width":40,"height":40,"mimetype":"image\/webp","extension":"webp"},"thumbnail":{"width":150,"height":150,"mimetype":"image\/webp","extension":"webp"},"medium":{"width":320,"height":320,"mimetype":"image\/webp","extension":"webp"},"large":{"width":1024,"height":1024,"mimetype":"image\/webp","extension":"webp"},"feed":{"width":1400,"height":1400},"id3":{"width":500,"height":500},"og":{"width":1200,"height":1200},"federation":{"width":400,"height":400},"webmanifest192":{"width":192,"height":192,"mimetype":"image\/png","extension":"png"},"webmanifest512":{"width":512,"height":512,"mimetype":"image\/png","extension":"png"}}}', + 'type' => 'image', + 'description' => null, + 'language_code' => null, + 'uploaded_by' => 1, + 'updated_by' => 1, + 'uploaded_at' => '2022-06-13 8:00:00', + 'updated_at' => '2022-06-13 8:00:00', + ]; + } + + /** + * @return array{id: int, file_key: string, file_size: int, file_mimetype: string, file_metadata: string, type: string, description: null, language_code: null, uploaded_by: int, updated_by: int, uploaded_at: string, updated_at: string} + */ + public static function banner(): array + { + return [ + 'id' => 2, + 'file_key' => 'podcasts/Handle/banner.jpg', + 'file_size' => 400000, + 'file_mimetype' => 'image/jpeg', + 'file_metadata' => '{"FILE":{"FileName":"banner.jpg","FileDateTime":1654861724,"FileSize":98209,"FileType":2,"MimeType":"image\/jpeg","SectionsFound":""},"COMPUTED":{"html":"width=\"1500\" height=\"500\"","Height":500,"Width":1500,"IsColor":1},"sizes":{"small":{"width":320,"height":128,"mimetype":"image\/webp","extension":"webp"},"medium":{"width":960,"height":320,"mimetype":"image\/webp","extension":"webp"},"federation":{"width":1500,"height":500}}}', + 'type' => 'image', + 'description' => null, + 'language_code' => null, + 'uploaded_by' => 1, + 'updated_by' => 1, + 'uploaded_at' => '2022-06-13 8:00:00', + 'updated_at' => '2022-06-13 8:00:00', + ]; + } + + /** + * @return array{id: int, uri: string, username: string, domain: string|false, private_key: string, public_key: string, display_name: string, summary: string, avatar_image_url: string, avatar_image_mimetype: string, cover_image_url: null, cover_image_mimetype: null, inbox_url: string, outbox_url: string, followers_url: string, followers_count: int, posts_count: int, is_blocked: int, created_at: string, updated_at: string} + */ + public static function actor(): array + { + return [ + 'id' => 1, + 'uri' => getenv('app_baseURL') . '@Handle', + 'username' => 'Handle', + 'domain' => getenv('app_baseURL'), + 'private_key' => 'private_key', + 'public_key' => 'public_key', + 'display_name' => 'Title', + 'summary' => '

    description

    ', + 'avatar_image_url' => getenv('app_baseURL') . 'media/podcasts/Handle', + 'avatar_image_mimetype' => 'image/webp', + 'cover_image_url' => null, + 'cover_image_mimetype' => null, + 'inbox_url' => getenv('app_baseURL') . '@Handle/inbox', + 'outbox_url' => getenv('app_baseURL') . '@Handle/outbox', + 'followers_url' => getenv('app_baseURL') . '@Handle/followers', + 'followers_count' => 0, + 'posts_count' => 0, + 'is_blocked' => 0, + 'created_at' => '2022-06-13 8:00:00', + 'updated_at' => '2022-06-13 8:00:00', + ]; + } + + /** + * @return array{id: int, guid: string, actor_id: int, handle: string, title: string, description_markdown: string, description_html: string, cover_id: int, banner_id: int, language_code: string, category_id: int, parental_advisory: null, owner_name: string, owner_email: string, publisher: string, type: string, copyright: string, is_blocked: int, is_completed: int, is_locked: int, imported_feed_url: null, new_feed_url: null, location_name: null, location_geo: null, location_osm: null, is_published_on_hubs: int, created_by: int, updated_by: int, created_at: string, updated_at: string} + */ + public static function podcast(): array + { + return [ + 'id' => 1, + 'guid' => '0d341200-0234-5de7-99a6-a7d02bea4ce2', + 'actor_id' => 1, + 'handle' => 'Handle', + 'title' => 'Title', + 'description_markdown' => 'description', + 'description_html' => '

    description

    ', + 'cover_id' => 1, + 'banner_id' => 2, + 'language_code' => 'en', + 'category_id' => 1, + 'parental_advisory' => null, + 'owner_name' => 'Owner', + 'owner_email' => 'Owner@gmail.com', + 'publisher' => '', + 'type' => 'episodic', + 'copyright' => '', + 'is_blocked' => 0, + 'is_completed' => 0, + 'is_locked' => 1, + 'imported_feed_url' => null, + 'new_feed_url' => null, + 'location_name' => null, + 'location_geo' => null, + 'location_osm' => null, + 'is_published_on_hubs' => 0, + 'created_by' => 1, + 'updated_by' => 1, + 'created_at' => '2022-06-13 8:00:00', + 'updated_at' => '2022-06-13 8:00:00', + ]; + } + + /** + * @return array{id:int,podcast_id:int,guid:string,title:string,slug:string,audio_id:int,description_markdown:string,description_html:string,cover_id:int,transcript_id:null,transcript_remote_url:null,chapters_id:null,chapters_remote_url:null,parental_advisory:null,number:int,season_number:null,type:string,is_blocked:false,location_name:null,location_geo:null,location_osm:null,is_published_on_hubs:false,posts_count:int,comments_count:int,is_premium:false,created_by:int,updated_by:int,published_at:null,created_at:string,updated_at:string} + */ + public static function episode(): array + { + return [ + 'id' => 1, + 'podcast_id' => 1, + 'guid' => 'http://localhost:8080/@test/episodes/muzyka-marzen', + 'title' => 'Episode title', + 'slug' => 'episode-slug', + 'audio_id' => 3, + 'description_markdown' => '123', + 'description_html' => '

    123

    ', + 'cover_id' => 1, + 'transcript_id' => null, + 'transcript_remote_url' => null, + 'chapters_id' => null, + 'chapters_remote_url' => null, + 'parental_advisory' => null, + 'number' => 1, + 'season_number' => null, + 'type' => 'full', + 'is_blocked' => false, + 'location_name' => null, + 'location_geo' => null, + 'location_osm' => null, + 'is_published_on_hubs' => false, + 'posts_count' => 0, + 'comments_count' => 0, + 'is_premium' => false, + 'created_by' => 1, + 'updated_by' => 1, + 'published_at' => null, + 'created_at' => '2023-05-31 11:16:06', + 'updated_at' => '2023-05-31 11:16:06', + ]; + } + + #[Override] + public function run(): void + { + $this->call(AppSeeder::class); + $this->call(DevSeeder::class); + $this->db->table('media') + ->insert(self::cover()); + $this->db->table('media') + ->insert(self::banner()); + $this->db->table('media') + ->insert(self::audio()); + $this->db->table('fediverse_actors') + ->insert(self::actor()); + $this->db->table('podcasts') + ->insert(self::podcast()); + $this->db->table('episodes') + ->insert(self::episode()); + } +} diff --git a/tests/_support/DatabaseTestCase.php b/tests/_support/DatabaseTestCase.php deleted file mode 100644 index 76b8b721..00000000 --- a/tests/_support/DatabaseTestCase.php +++ /dev/null @@ -1,61 +0,0 @@ - */ protected $allowedFields = ['name', 'uid', 'class', 'icon', 'summary']; @@ -39,12 +39,12 @@ class ExampleModel extends Model protected $useTimestamps = true; /** - * @var mixed[] + * @var array|string>|string>|string */ protected $validationRules = []; /** - * @var mixed[] + * @var array> */ protected $validationMessages = []; diff --git a/tests/_support/SessionTestCase.php b/tests/_support/SessionTestCase.php deleted file mode 100644 index 19e18bfd..00000000 --- a/tests/_support/SessionTestCase.php +++ /dev/null @@ -1,41 +0,0 @@ -mockSession(); - } - - /** - * Pre-loads the mock session driver into $this->session. - * - * @var string - */ - protected function mockSession(): void - { - $config = config('App'); - $this->session = new MockSession(new ArrayHandler($config, '0.0.0.0'), $config,); - Services::injectMock('session', $this->session); - } -} diff --git a/tests/database/ExampleDatabaseTest.php b/tests/database/ExampleDatabaseTest.php index 00b27097..eda4a6eb 100644 --- a/tests/database/ExampleDatabaseTest.php +++ b/tests/database/ExampleDatabaseTest.php @@ -4,17 +4,20 @@ declare(strict_types=1); namespace Tests\Database; -use Tests\Support\DatabaseTestCase; +use CodeIgniter\Database\Seeder; +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\DatabaseTestTrait; +use Tests\Support\Database\Seeds\ExampleSeeder; use Tests\Support\Models\ExampleModel; -class ExampleDatabaseTest extends DatabaseTestCase +class ExampleDatabaseTest extends CIUnitTestCase { - protected function setUp(): void - { - parent::setUp(); + use DatabaseTestTrait; - // Extra code to run before each test - } + /** + * @var class-string|list> + */ + protected $seed = ExampleSeeder::class; public function testModelFindAll(): void { @@ -34,9 +37,15 @@ class ExampleDatabaseTest extends DatabaseTestCase $this->setPrivateProperty($model, 'tempUseSoftDeletes', true); $object = $model->first(); + + if (! is_object($object)) { + return; + } + $model->delete($object->id); // The model should no longer find it + // @phpstan-ignore-next-line $this->assertNull($model->find($object->id)); // ... but it should still be in the database diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 00000000..cf672743 --- /dev/null +++ b/tests/index.html @@ -0,0 +1,9 @@ + + + + 403 Forbidden + + +

    Directory access is forbidden.

    + + diff --git a/tests/modules/Api/Rest/V1/EpisodeTest.php b/tests/modules/Api/Rest/V1/EpisodeTest.php new file mode 100644 index 00000000..990652f7 --- /dev/null +++ b/tests/modules/Api/Rest/V1/EpisodeTest.php @@ -0,0 +1,120 @@ +|list> + */ + protected $seed = FakeSinglePodcastApiSeeder::class; + + /** + * @var string + */ + protected $basePath = 'app/Database'; + + /** + * @var array + */ + private array $episode = []; + + private string $apiUrl = ''; + + #[Override] + protected function setUp(): void + { + parent::setUp(); + + $this->episode = FakeSinglePodcastApiSeeder::episode(); + + $this->episode['created_at'] = []; + $this->episode['updated_at'] = []; + $this->apiUrl = config('RestApi') + ->gateway; + } + + #[Override] + protected function tearDown(): void + { + parent::tearDown(); + + restore_error_handler(); + restore_exception_handler(); + } + + public function testList(): void + { + $result = $this->call('get', $this->apiUrl . 'episodes'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONFragment([ + 0 => $this->episode, + ]); + } + + public function testView(): void + { + $result = $this->call('get', $this->apiUrl . 'episodes/1'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONFragment($this->episode); + } + + public function testViewNotFound(): void + { + $result = $this->call('get', $this->apiUrl . 'episodes/2'); + $result->assertStatus(404); + $result->assertJSONExact( + [ + 'status' => 404, + 'error' => 404, + 'messages' => [ + 'error' => 'Episode not found', + ], + ], + ); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + } + + /* + * Refreshing database to fetch empty array of episodes + */ + public function testListEmpty(): void + { + $this->regressDatabase(); + $this->migrateDatabase(); + $result = $this->call('get', $this->apiUrl . 'episodes'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONExact([]); + $this->seed($this->seed); + } +} diff --git a/tests/modules/Api/Rest/V1/PodcastTest.php b/tests/modules/Api/Rest/V1/PodcastTest.php new file mode 100644 index 00000000..cdf5a446 --- /dev/null +++ b/tests/modules/Api/Rest/V1/PodcastTest.php @@ -0,0 +1,119 @@ +|list> + */ + protected $seed = FakeSinglePodcastApiSeeder::class; + + /** + * @var string + */ + protected $basePath = 'app/Database'; + + /** + * @var array + */ + private array $podcast = []; + + private string $podcastApiUrl = ''; + + #[Override] + protected function setUp(): void + { + parent::setUp(); + + $this->podcast = FakeSinglePodcastApiSeeder::podcast(); + $this->podcast['created_at'] = []; + $this->podcast['updated_at'] = []; + $this->podcastApiUrl = config('RestApi') + ->gateway; + } + + #[Override] + protected function tearDown(): void + { + parent::tearDown(); + + restore_error_handler(); + restore_exception_handler(); + } + + public function testList(): void + { + $result = $this->call('get', $this->podcastApiUrl . 'podcasts'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONFragment([ + 0 => $this->podcast, + ]); + } + + public function testView(): void + { + $result = $this->call('get', $this->podcastApiUrl . 'podcasts/1'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONFragment($this->podcast); + } + + public function testViewNotFound(): void + { + $result = $this->call('get', $this->podcastApiUrl . 'podcasts/2'); + $result->assertStatus(404); + $result->assertJSONExact( + [ + 'status' => 404, + 'error' => 404, + 'messages' => [ + 'error' => 'Podcast not found', + ], + ], + ); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + } + + /* + * Refreshing database to fetch empty array of podcasts + */ + public function testListEmpty(): void + { + $this->regressDatabase(); + $this->migrateDatabase(); + $result = $this->call('get', $this->podcastApiUrl . 'podcasts'); + $result->assertStatus(200); + $result->assertHeader('Content-Type', 'application/json; charset=UTF-8'); + $result->assertJSONExact([]); + $this->seed($this->seed); + } +} diff --git a/tests/modules/Plugins/ManifestTest.php b/tests/modules/Plugins/ManifestTest.php new file mode 100644 index 00000000..c5557e9b --- /dev/null +++ b/tests/modules/Plugins/ManifestTest.php @@ -0,0 +1,67 @@ +assertNotEquals($manifest->name, 'acme/hello-world'); + $this->assertNotEquals($manifest->version, '1.0.0'); + + $manifest->loadFromFile(TESTPATH . 'modules/Plugins/mocks/manifests/manifest-required.json'); + + // no errors + $this->assertEmpty($manifest->getPluginErrors('acme/hello-world')); + + // properties have been set + $this->assertEquals($manifest->name, 'acme/hello-world'); + $this->assertEquals($manifest->version, '1.0.0'); + } + + public function testLoadEmptyData(): void + { + $manifest = new Manifest('acme/hello-world'); + + $manifest->loadFromFile(TESTPATH . 'modules/Plugins/mocks/manifests/manifest-empty.json'); + + $errors = $manifest->getPluginErrors('acme/hello-world'); + + $this->assertCount(2, $errors); + + // missing required name and version + $this->assertArrayHasKey('name', $errors); + $this->assertArrayHasKey('version', $errors); + } + + public function testLoadValidData(): void + { + $manifest = new Manifest('acme/hello-world'); + + $manifest->loadFromFile(TESTPATH . 'modules/Plugins/mocks/manifests/manifest-full-valid.json'); + + // no errors + $this->assertEmpty($manifest->getPluginErrors('acme/hello-world')); + } + + public function testLoadInvalidData(): void + { + $manifest = new Manifest('acme/hello-world'); + + $manifest->loadFromFile(TESTPATH . 'modules/Plugins/mocks/manifests/manifest-full-invalid.json'); + + // errors + $this->assertNotEmpty($manifest->getPluginErrors('acme/hello-world')); + } +} diff --git a/tests/modules/Plugins/PluginsTest.php b/tests/modules/Plugins/PluginsTest.php new file mode 100644 index 00000000..4594bbbe --- /dev/null +++ b/tests/modules/Plugins/PluginsTest.php @@ -0,0 +1,190 @@ +folder = __DIR__ . '/mocks/plugins' . DIRECTORY_SEPARATOR; + + self::$plugins = new Plugins($pluginsConfig); + } + + public function testRegister(): void + { + $this->assertCount(7, self::$plugins->getAllPlugins()); + $this->assertEquals(7, self::$plugins->getInstalledCount()); + $this->assertEquals(0, self::$plugins->getActiveCount()); + } + + public function testActivateDeactivate(): void + { + $this->assertEquals(0, self::$plugins->getActiveCount()); + + $plugin = self::$plugins->getAllPlugins()[0]; + + // get first plugin and activate it + self::$plugins->activate($plugin); + + $this->assertEquals(1, self::$plugins->getActiveCount()); + $this->assertEquals(PluginStatus::ACTIVE, $plugin->getStatus()); + $this->seeInDatabase('settings', [ + 'class' => PluginsConfig::class, + 'key' => 'active', + 'value' => '1', + 'type' => 'boolean', + 'context' => 'plugin:' . $plugin->getKey(), + ]); + + // get first plugin and deactivate it + self::$plugins->deactivate($plugin); + + $this->assertEquals(0, self::$plugins->getActiveCount()); + $this->assertEquals(PluginStatus::INACTIVE, $plugin->getStatus()); + $this->seeInDatabase('settings', [ + 'class' => PluginsConfig::class, + 'key' => 'active', + 'value' => '0', + 'type' => 'boolean', + 'context' => 'plugin:' . $plugin->getKey(), + ]); + } + + public function testRunHooksActive(): void + { + $acmeAllHooksPlugin = self::$plugins->getPlugin('acme', 'all-hooks'); + + self::$plugins->activate($acmeAllHooksPlugin); + + $this->assertEquals(1, self::$plugins->getActiveCount()); + + $podcast = new Podcast(); + $this->assertEquals('', $podcast->title); + self::$plugins->runHook('rssBeforeChannel', [$podcast]); + $this->assertEquals('Podcast test', $podcast->title); + + $channel = new RssFeed(''); + $this->assertTrue(empty($channel->foo)); + self::$plugins->runHook('rssAfterChannel', [$podcast, $channel]); + $this->assertFalse(empty($channel->foo)); + + $episode = new Episode(); + $this->assertEquals('', $episode->title); + self::$plugins->runHook('rssBeforeItem', [$episode]); + $this->assertEquals('Episode test', $episode->title); + + $item = new RssFeed(''); + $this->assertTrue(empty($item->efoo)); + self::$plugins->runHook('rssAfterItem', [$episode, $item]); + $this->assertFalse(empty($item->efoo)); + + $head = new HtmlHead(); + self::$plugins->runHook('siteHead', [$head]); + + $this->assertEquals( + (string) $head, + ' foo foo ', + ); + } + + public function testRunHooksInactive(): void + { + $acmeAllHooksPlugin = self::$plugins->getPlugin('acme', 'all-hooks'); + + self::$plugins->deactivate($acmeAllHooksPlugin); + + $this->assertEquals(0, self::$plugins->getActiveCount()); + + // nothing should change when running hooks as the plugin is inactive + + $podcast = new Podcast(); + $this->assertEquals('', $podcast->title); + self::$plugins->runHook('rssBeforeChannel', [$podcast]); + $this->assertEquals('', $podcast->title); + + $channel = new RssFeed(''); + $this->assertTrue(empty($channel->foo)); + self::$plugins->runHook('rssAfterChannel', [$podcast, $channel]); + $this->assertTrue(empty($channel->foo)); + + $episode = new Episode(); + $this->assertEquals('', $episode->title); + self::$plugins->runHook('rssBeforeItem', [$episode]); + $this->assertEquals('', $episode->title); + + $item = new RssFeed(''); + $this->assertTrue(empty($item->efoo)); + self::$plugins->runHook('rssAfterItem', [$episode, $item]); + $this->assertTrue(empty($item->efoo)); + + ob_start(); + self::$plugins->runHook('siteHead', []); + $result = ob_get_contents(); + ob_end_clean(); //Discard output buffer + $this->assertEquals('', $result); + } + + public function testRunUndeclaredHook(): void + { + $acmeUndeclaredHookPlugin = self::$plugins->getPlugin('acme', 'undeclared-hook'); + + self::$plugins->activate($acmeUndeclaredHookPlugin); + + $podcast = new Podcast(); + $this->assertEquals('', $podcast->title); + self::$plugins->runHook('rssBeforeChannel', [$podcast]); + $this->assertEquals('Podcast test undeclared', $podcast->title); + + // rssAfterChannel has not been declared in plugin manifest, should not be running + $channel = new RssFeed(''); + $this->assertTrue(empty($channel->foo)); + self::$plugins->runHook('rssAfterChannel', [$podcast, $channel]); + $this->assertTrue(empty($channel->foo)); + } +} diff --git a/tests/modules/Plugins/mocks/manifests/manifest-empty.json b/tests/modules/Plugins/mocks/manifests/manifest-empty.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/modules/Plugins/mocks/manifests/manifest-empty.json @@ -0,0 +1 @@ +{} diff --git a/tests/modules/Plugins/mocks/manifests/manifest-full-invalid.json b/tests/modules/Plugins/mocks/manifests/manifest-full-invalid.json new file mode 100644 index 00000000..e13a5bc0 --- /dev/null +++ b/tests/modules/Plugins/mocks/manifests/manifest-full-invalid.json @@ -0,0 +1,120 @@ +{ + "name": "acme/hello-world", + "description": true, + "version": "1.0.0", + "authors": [ + { + "name": "Acme Corporation", + "email": "acme@example.com", + "url": "https://example.com/" + } + ], + "homepage": "https://example.com/", + "license": ["MIT", "AGPLv3"], + "keywords": ["seo", "analytics"], + "hooks": ["rssAfterChannel"], + "settings": { + "general": { + "name": { + "type": "radio-group", + "label": "Name", + "options": { + "foo": { "label": "Foo", "hint": "This is a hint." }, + "bar": { "label": "Bar" } + } + }, + "email": { + "type": "email", + "label": "Email" + }, + "url": { + "type": "url", + "label": "Your website URL" + }, + "toggler": { + "type": "toggler", + "label": "Toggle this?" + }, + "number": { + "type": "number", + "label": "Number" + }, + "datetime": { + "type": "datetime", + "label": "Enter a date", + "optional": true + }, + "select": { + "type": "select", + "label": "Select something", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "select-multiple": { + "type": "select-multiple", + "label": "Select multiple things", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "radio-group": { + "type": "radio-group", + "label": "Radio Group", + "helper": "This is a helper.", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "texting": { + "type": "textarea", + "label": "Your text", + "hint": "This is a hint." + }, + "hello": { + "type": "markdown", + "label": "Name Podcast", + "hint": "This is a hint.", + "optional": true + } + }, + "podcast": { + "name": { + "type": "text", + "label": "Name Podcast", + "hint": "This is a hint." + } + }, + "episode": { + "name": { + "type": "text", + "label": "Name Episode", + "helper": "This is a helper." + } + } + } +} diff --git a/tests/modules/Plugins/mocks/manifests/manifest-full-valid.json b/tests/modules/Plugins/mocks/manifests/manifest-full-valid.json new file mode 100644 index 00000000..f8223ba3 --- /dev/null +++ b/tests/modules/Plugins/mocks/manifests/manifest-full-valid.json @@ -0,0 +1,121 @@ +{ + "name": "acme/hello-world", + "description": "A Castopod plugin to add a hello world greeting to your RSS feed!", + "version": "1.0.0", + "authors": [ + { + "name": "Acme Corporation", + "email": "acme@example.com", + "url": "https://example.com/" + } + ], + "homepage": "https://example.com/", + "license": "MIT", + "keywords": ["seo", "analytics"], + "hooks": ["rssAfterChannel"], + "settings": { + "general": { + "name": { + "type": "radio-group", + "label": "Name", + "options": { + "foo": { "label": "Foo", "hint": "This is a hint." }, + "bar": { "label": "Bar" }, + "baz": { "label": "Baz" } + } + }, + "email": { + "type": "email", + "label": "Email" + }, + "url": { + "type": "url", + "label": "Your website URL" + }, + "toggler": { + "type": "toggler", + "label": "Toggle this?" + }, + "number": { + "type": "number", + "label": "Number" + }, + "datetime": { + "type": "datetime", + "label": "Enter a date", + "optional": true + }, + "select": { + "type": "select", + "label": "Select something", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "select-multiple": { + "type": "select-multiple", + "label": "Select multiple things", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "radio-group": { + "type": "radio-group", + "label": "Radio Group", + "helper": "This is a helper.", + "options": { + "foo": { + "label": "Foo" + }, + "bar": { + "label": "Bar" + }, + "baz": { + "label": "Baz" + } + } + }, + "textarea": { + "type": "textarea", + "label": "Your text", + "hint": "This is a hint." + }, + "markdown": { + "type": "markdown", + "label": "Markdown", + "hint": "This is a hint.", + "optional": true + } + }, + "podcast": { + "name": { + "type": "text", + "label": "Name Podcast", + "hint": "This is a hint." + } + }, + "episode": { + "name": { + "type": "text", + "label": "Name Episode", + "helper": "This is a helper." + } + } + } +} diff --git a/tests/modules/Plugins/mocks/manifests/manifest-required.json b/tests/modules/Plugins/mocks/manifests/manifest-required.json new file mode 100644 index 00000000..5272f045 --- /dev/null +++ b/tests/modules/Plugins/mocks/manifests/manifest-required.json @@ -0,0 +1,4 @@ +{ + "name": "acme/hello-world", + "version": "1.0.0" +} diff --git a/tests/modules/Plugins/mocks/plugins/acme/all-hooks/Plugin.php b/tests/modules/Plugins/mocks/plugins/acme/all-hooks/Plugin.php new file mode 100644 index 00000000..53c93cdc --- /dev/null +++ b/tests/modules/Plugins/mocks/plugins/acme/all-hooks/Plugin.php @@ -0,0 +1,42 @@ +title = 'Podcast test'; + } + + #[Override] + public function rssAfterChannel(Podcast $podcast, RssFeed $channel): void + { + $channel->addChild('foo', 'bar'); + } + + #[Override] + public function rssBeforeItem(Episode $episode): void + { + $episode->title = 'Episode test'; + } + + #[Override] + public function rssAfterItem(Episode $episode, RssFeed $item): void + { + $item->addChild('efoo', 'ebar'); + } + + #[Override] + public function siteHead(HtmlHead $head): void + { + $head->tag('title', 'foo'); + } +} diff --git a/tests/modules/Plugins/mocks/plugins/acme/all-hooks/manifest.json b/tests/modules/Plugins/mocks/plugins/acme/all-hooks/manifest.json new file mode 100644 index 00000000..b564821b --- /dev/null +++ b/tests/modules/Plugins/mocks/plugins/acme/all-hooks/manifest.json @@ -0,0 +1,11 @@ +{ + "name": "acme/all-hooks", + "version": "1.0.0", + "hooks": [ + "rssBeforeChannel", + "rssAfterChannel", + "rssBeforeItem", + "rssAfterItem", + "siteHead" + ] +} diff --git a/tests/modules/Plugins/mocks/plugins/acme/empty-manifest/Plugin.php b/tests/modules/Plugins/mocks/plugins/acme/empty-manifest/Plugin.php new file mode 100644 index 00000000..4aaf8422 --- /dev/null +++ b/tests/modules/Plugins/mocks/plugins/acme/empty-manifest/Plugin.php @@ -0,0 +1,9 @@ +title = 'Podcast test undeclared'; + } + + #[Override] + public function rssAfterChannel(Podcast $podcast, RssFeed $channel): void + { + $channel->addChild('foo', 'bar'); + } +} diff --git a/tests/modules/Plugins/mocks/plugins/acme/undeclared-hook/manifest.json b/tests/modules/Plugins/mocks/plugins/acme/undeclared-hook/manifest.json new file mode 100644 index 00000000..af9293ae --- /dev/null +++ b/tests/modules/Plugins/mocks/plugins/acme/undeclared-hook/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "acme/all-hooks", + "version": "1.0.0", + "hooks": ["rssBeforeChannel"] +} diff --git a/tests/modules/Plugins/mocks/plugins/atlantis/empty/.gitkeep b/tests/modules/Plugins/mocks/plugins/atlantis/empty/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/Plugins/mocks/plugins/atlantis/hello-broken/Plugin.php b/tests/modules/Plugins/mocks/plugins/atlantis/hello-broken/Plugin.php new file mode 100644 index 00000000..8309b442 --- /dev/null +++ b/tests/modules/Plugins/mocks/plugins/atlantis/hello-broken/Plugin.php @@ -0,0 +1,9 @@ +session->set('logged_in', 123); + $session = service('session'); - $value = $this->session->get('logged_in'); - - $this->assertSame(123, $value); + $session->set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); } } diff --git a/tests/unit/HealthTest.php b/tests/unit/HealthTest.php index 0095448d..db2b46eb 100644 --- a/tests/unit/HealthTest.php +++ b/tests/unit/HealthTest.php @@ -2,35 +2,30 @@ declare(strict_types=1); -namespace Tests\Unit; - use CodeIgniter\Test\CIUnitTestCase; use Config\App; -use Config\Services; use Tests\Support\Libraries\ConfigReader; -class HealthTest extends CIUnitTestCase +/** + * @internal + */ +final class HealthTest extends CIUnitTestCase { - protected function setUp(): void - { - parent::setUp(); - } - public function testIsDefinedAppPath(): void { - $test = defined('APPPATH'); - - $this->assertTrue($test); + /** @phpstan-ignore method.alreadyNarrowedType */ + $this->assertTrue(defined('APPPATH')); } public function testBaseUrlHasBeenSet(): void { - $validation = Services::validation(); + $validation = service('validation'); + $env = false; // Check the baseURL in .env if (is_file(HOMEPATH . '.env')) { - $env = (bool) preg_grep('~^app\.baseURL = .~', file(HOMEPATH . '.env'),); + $env = preg_grep('~^app\.baseURL = .~', file(HOMEPATH . '.env')) !== false; } if ($env) { @@ -39,7 +34,7 @@ class HealthTest extends CIUnitTestCase // So if you set app.baseURL in .env, it takes precedence $config = new App(); $this->assertTrue( - $validation->check($config->baseURL, 'valid_url'), + $validation->check($config->baseURL, 'valid_url_strict'), 'baseURL "' . $config->baseURL . '" in .env is not valid URL', ); } @@ -50,10 +45,8 @@ class HealthTest extends CIUnitTestCase // BaseURL in app/Config/App.php is a valid URL? $this->assertTrue( - $validation->check($reader->baseURL, 'valid_url'), - 'baseURL "' . - $reader->baseURL . - '" in app/Config/App.php is not valid URL', + $validation->check($reader->baseURL, 'valid_url_strict'), + 'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL', ); } } diff --git a/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php new file mode 100644 index 00000000..6f78c843 --- /dev/null +++ b/themes/cp_admin/_layout.php @@ -0,0 +1,64 @@ + + + + + + + + + include('_partials/_nav_header') ?> + include('_partials/_nav_aside') ?> +
    +
    +
    + +
    +
    + is_premium) || ($isPodcastArea && $podcast->is_premium)): ?> +
    + + is_premium) ? lang('PremiumPodcasts.episode_is_premium') : lang('PremiumPodcasts.podcast_is_premium') ?> + renderSection('pageTitle') ?> +
    + + renderSection('pageTitle') ?> + + renderSection('headerLeft') ?> +
    +
    renderSection('headerRight') ?>
    +
    +
    + renderSection('subtitle') ?> +
    + + get('Import.current') === $podcast->handle): ?> +
    + + publication_status !== 'published'): ?> + published_at, $podcast->id, $podcast->publication_status) ?> + + + publication_status !== 'published'): ?> + + +
    + + renderSection('content') ?> +
    +
    + \ No newline at end of file diff --git a/themes/cp_admin/_message_block.php b/themes/cp_admin/_message_block.php new file mode 100644 index 00000000..42a34097 --- /dev/null +++ b/themes/cp_admin/_message_block.php @@ -0,0 +1,33 @@ +has('message')): ?> + + + +has('error')): ?> + + + +has('errors')): ?> + +
      + +
    • + +
    +
    + + +has('warning')): ?> + + + +has('warnings')): ?> + +
      + +
    • + +
    +
    + diff --git a/themes/cp_admin/_partials/_nav_aside.php b/themes/cp_admin/_partials/_nav_aside.php new file mode 100644 index 00000000..0f2867b1 --- /dev/null +++ b/themes/cp_admin/_partials/_nav_aside.php @@ -0,0 +1,24 @@ + + + + diff --git a/themes/cp_admin/_partials/_nav_header.php b/themes/cp_admin/_partials/_nav_header.php new file mode 100644 index 00000000..38e25d2b --- /dev/null +++ b/themes/cp_admin/_partials/_nav_header.php @@ -0,0 +1,158 @@ +user()); ?> + +
    + + +
    + + 'html', + 'content' => esc(<<{$notificationsTitle} + HTML), + ], +]; + +if ($userPodcasts !== []) { + foreach ($userPodcasts as $userPodcast) { + $userPodcastTitle = esc($userPodcast->title); + + $unreadNotificationDotDisplayClass = in_array($userPodcast->actor_id, $actorIdsWithUnreadNotifications, true) ? '' : 'hidden'; + + $items[] = [ + 'type' => 'link', + 'title' => << +
    + + +
    + {$userPodcastTitle} +
    + HTML + , + 'uri' => route_to('notification-list', $userPodcast->id), + ]; + } +} else { + $noNotificationsText = lang('Notifications.no_notifications'); + $items[] = [ + 'type' => 'html', + 'content' => esc(<<{$noNotificationsText} + HTML), + ]; +} +?> + + + +

    + actor_id ? icon('check-fill', [ + 'class' => 'ml-2 bg-accent-base text-accent-contrast rounded-full', + ]) : ''; + $userPodcastTitle = esc($userPodcast->title); + + $interactButtons .= << +
    {$userPodcastTitle}{$checkMark}
    + + HTML; +} + +$interactAsText = lang('Common.choose_interact'); +$interactAsRoute = route_to('interact-as-actor'); +$csrfField = csrf_field(); + +$menuItems = [ + [ + 'type' => 'link', + 'title' => lang('Navigation.account.my-account'), + 'uri' => route_to('my-account'), + ], + [ + 'type' => 'link', + 'title' => lang('Navigation.account.change-password'), + 'uri' => route_to('change-password'), + ], + [ + 'type' => 'separator', + ], + [ + 'type' => 'link', + 'title' => lang('Navigation.account.logout'), + 'uri' => route_to('logout'), + ], +]; + +if ($userPodcasts !== []) { + $menuItems = array_merge([ + [ + 'type' => 'html', + 'content' => esc(<< + {$interactAsText} +
    + {$csrfField} + {$interactButtons} +
    + + HTML), + ], + [ + 'type' => 'separator', + ], + ], $menuItems); +} +?> + + \ No newline at end of file diff --git a/themes/cp_admin/_partials/_nav_menu.php b/themes/cp_admin/_partials/_nav_menu.php new file mode 100644 index 00000000..a646b81c --- /dev/null +++ b/themes/cp_admin/_partials/_nav_menu.php @@ -0,0 +1,65 @@ + diff --git a/themes/cp_admin/_partials/_user_info.php b/themes/cp_admin/_partials/_user_info.php new file mode 100644 index 00000000..6bb3aebb --- /dev/null +++ b/themes/cp_admin/_partials/_user_info.php @@ -0,0 +1,32 @@ +
    +
    + +
    +
    + username) ?> +
    +
    +
    +
    + +
    +
    + email ?> +
    +
    +
    +
    + +
    +
    + getGroups()) ?> +
    +
    +
    +
    + +
    +
    + getPermissions()) ?> +
    +
    diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php new file mode 100644 index 00000000..76c80c5e --- /dev/null +++ b/themes/cp_admin/_sidebar.php @@ -0,0 +1,105 @@ + [ + 'icon' => 'dashboard-fill', // @icon("dashboard-fill") + 'items' => ['admin'], + ], + 'podcasts' => [ + 'icon' => 'mic-fill', // @icon("mic-fill") + 'items' => ['podcast-list', 'podcast-create', 'all-podcast-imports', 'podcast-imports-add'], + 'items-permissions' => [ + 'podcast-create' => 'podcasts.create', + 'all-podcast-imports' => 'podcasts.import', + 'podcast-imports-add' => 'podcasts.import', + ], + 'add-cta' => 'podcast-create', + 'count-route' => 'podcast-list', + ], + 'plugins' => [ + 'icon' => 'puzzle-fill', // @icon("puzzle-fill") + 'items' => ['plugins-installed'], + 'items-labels' => [ + 'plugins-installed' => lang('Navigation.plugins-installed') . ' (' . service('plugins')->getInstalledCount() . ')', + ], + 'items-permissions' => [ + 'plugins-installed' => 'plugins.manage', + ], + 'count' => service('plugins')->getActiveCount(), + 'count-route' => 'plugins-installed', + ], + 'persons' => [ + 'icon' => 'folder-user-fill', // @icon("folder-user-fill") + 'items' => ['person-list', 'person-create'], + 'items-permissions' => [ + 'person-list' => 'persons.manage', + 'person-create' => 'persons.manage', + ], + 'add-cta' => 'person-create', + 'count' => (new PersonModel())->countAllResults(), + 'count-route' => 'person-list', + ], + 'fediverse' => [ + 'icon' => 'rocket-2-fill', // @icon("rocket-2-fill") + 'items' => ['fediverse-blocked-actors', 'fediverse-blocked-domains'], + 'items-permissions' => [ + 'fediverse-blocked-actors' => 'fediverse.manage-blocks', + 'fediverse-blocked-domains' => 'fediverse.manage-blocks', + ], + ], + 'users' => [ + 'icon' => 'group-fill', // @icon("group-fill") + 'items' => ['user-list', 'user-create'], + 'items-permissions' => [ + 'user-list' => 'users.manage', + 'user-create' => 'users.manage', + ], + 'add-cta' => 'user-create', + 'count' => (new UserModel())->countAllResults(), + 'count-route' => 'user-list', + ], + 'pages' => [ + 'icon' => 'pages-fill', // @icon("pages-fill") + 'items' => ['page-list', 'page-create'], + 'items-permissions' => [ + 'page-list' => 'pages.manage', + 'page-create' => 'pages.manage', + ], + 'add-cta' => 'page-create', + 'count' => (new PageModel())->countAllResults(), + 'count-route' => 'page-list', + ], + 'settings' => [ + 'icon' => 'settings-3-fill', // @icon("settings-3-fill") + 'items' => ['settings-general', 'settings-theme', 'admin-about'], + 'items-permissions' => [ + 'settings-general' => 'admin.settings', + 'settings-theme' => 'admin.settings', + 'admin-about' => 'admin.settings', + ], + ], +]; + +foreach (plugins()->getActivePlugins() as $plugin) { + $route = route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage()); + $navigation['plugins']['items'][] = $route; + $navigation['plugins']['items-labels'][$route] = $plugin->getTitle(); + $navigation['plugins']['items-permissions'][$route] = 'plugins.manage'; +} + +if (auth()->user()->can('podcasts.view')) { + $navigation['podcasts']['count'] = (new PodcastModel())->countAllResults(); +} else { + $navigation['podcasts']['count'] = count(get_user_podcasts(auth()->user())); +} ?> + + + $navigation, + 'langKey' => 'Navigation', +]) ?> diff --git a/themes/cp_admin/contributor/create.php b/themes/cp_admin/contributor/create.php new file mode 100644 index 00000000..123036f1 --- /dev/null +++ b/themes/cp_admin/contributor/create.php @@ -0,0 +1,34 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title)]) ?> +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/contributor/edit.php b/themes/cp_admin/contributor/edit.php new file mode 100644 index 00000000..33eb9101 --- /dev/null +++ b/themes/cp_admin/contributor/edit.php @@ -0,0 +1,26 @@ +extend('_layout') ?> + +section('pageTitle') ?> +username)]) ?> +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/contributor/list.php b/themes/cp_admin/contributor/list.php new file mode 100644 index 00000000..d8546fa1 --- /dev/null +++ b/themes/cp_admin/contributor/list.php @@ -0,0 +1,50 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + + lang('Contributor.list.username'), + 'cell' => function ($contributor) { + return esc($contributor->username); + }, + ], + [ + 'header' => lang('Contributor.list.role'), + 'cell' => function ($contributor, $podcast): string { + $role = get_group_info(get_podcast_group($contributor, $podcast->id), $podcast->id)['title']; + + if ($podcast->created_by === $contributor->id) { + $role = '
    ' . icon('shield-user-fill') . '' . $role . '
    '; + } + + return $role; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($contributor, $podcast) { + // @icon("pencil-fill") + // @icon("delete-bin-fill") + return '' . lang('Contributor.edit') . '' . + '' . lang('Contributor.remove') . ''; + }, + ], + ], + $podcast->contributors, + '', + $podcast, +) ?> + +endSection() ?> diff --git a/themes/cp_admin/contributor/remove.php b/themes/cp_admin/contributor/remove.php new file mode 100644 index 00000000..0f4fdea6 --- /dev/null +++ b/themes/cp_admin/contributor/remove.php @@ -0,0 +1,31 @@ +extend('_layout') ?> + +section('pageTitle') ?> + $contributor->username, +]) ?> +endSection() ?> + +section('content') ?> + +
    + + + $contributor->username, + 'podcastTitle' => $podcast->title, +]) ?> + + $contributor->username, + 'podcastTitle' => $podcast->title, +]) ?> + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/contributor/view.php b/themes/cp_admin/contributor/view.php new file mode 100644 index 00000000..fe0fa793 --- /dev/null +++ b/themes/cp_admin/contributor/view.php @@ -0,0 +1,27 @@ +extend('_layout') ?> + +section('pageTitle') ?> + esc($contributor->username), + 'podcastTitle' => esc($podcast->title), +]) ?> +endSection() ?> + +section('content') ?> +
    +
    + +
    +
    + username) ?> +
    +
    +
    +
    + +
    +
    + podcast_role ?> +
    +
    +endSection() ?> diff --git a/themes/cp_admin/dashboard.php b/themes/cp_admin/dashboard.php new file mode 100644 index 00000000..6a8a3bac --- /dev/null +++ b/themes/cp_admin/dashboard.php @@ -0,0 +1,43 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + % +
    + +
    + + +
    + + +asset('js/charts.ts', 'js') ?> +endsection() ?> diff --git a/themes/cp_admin/episode/_card.php b/themes/cp_admin/episode/_card.php new file mode 100644 index 00000000..51c87eda --- /dev/null +++ b/themes/cp_admin/episode/_card.php @@ -0,0 +1,79 @@ +
    + +
    +
    + <?= esc($episode->title) ?> +
    + is_premium): ?> +
    + 'w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg text-accent-contrast bg-accent-base', + ]) ?> + published_at, $episode->publication_status, 'text-sm'); ?> +
    + + published_at, $episode->publication_status, 'absolute top-0 left-0 ml-2 mt-2 text-sm'); ?> + +
    + number, $episode->season_number, 'text-xs font-semibold !no-underline px-1 bg-black/50 mr-1', true) ?> + title) ?> +
    +
    + + 'link', + 'title' => lang('Episode.go_to_page'), + 'uri' => route_to('episode', esc($episode->podcast->handle), esc($episode->slug)), + ], + [ + 'type' => 'link', + 'title' => lang('Episode.edit'), + 'uri' => route_to('episode-edit', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Episode.embed.title'), + 'uri' => route_to('embed-add', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Person.persons'), + 'uri' => route_to('episode-persons-manage', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('VideoClip.list.title'), + 'uri' => route_to('video-clips-list', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Soundbite.list.title'), + 'uri' => route_to('soundbites-list', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'separator', + ], + ]; +if ($episode->published_at === null) { + $items[] = [ + 'type' => 'link', + 'title' => lang('Episode.delete'), + 'uri' => route_to('episode-delete', $episode->podcast->id, $episode->id), + 'class' => 'font-semibold text-red-600', + ]; +} else { + $label = lang('Episode.delete'); + $icon = icon('forbid-fill', [ + 'class' => 'mr-2', + ]); + $title = lang('Episode.messages.unpublishBeforeDeleteTip'); + $items[] = [ + 'type' => 'html', + 'content' => esc(<<{$icon}{$label} + HTML), + ]; +} ?> + +
    \ No newline at end of file diff --git a/themes/cp_admin/episode/_sidebar.php b/themes/cp_admin/episode/_sidebar.php new file mode 100644 index 00000000..fd0ef42b --- /dev/null +++ b/themes/cp_admin/episode/_sidebar.php @@ -0,0 +1,89 @@ + [ + 'icon' => 'dashboard-fill', // @icon("dashboard-fill") + 'items' => ['episode-view', 'episode-edit', 'episode-persons-manage', 'embed-add'], + 'items-permissions' => [ + 'episode-view' => 'episodes.view', + 'episode-edit' => 'episodes.edit', + 'episode-persons-manage' => 'episodes.manage-persons', + 'embed-add' => 'episodes.edit', + ], + ], + 'plugins' => [ + 'icon' => 'puzzle-fill', // @icon("puzzle-fill") + 'items' => [], + 'items-labels' => [], + 'items-permissions' => [], + ], + 'clips' => [ + 'icon' => 'clapperboard-fill', // @icon("clapperboard-fill") + 'items' => ['video-clips-list', 'video-clips-create', 'soundbites-list', 'soundbites-create'], + 'items-permissions' => [ + 'video-clips-list' => 'episodes.manage-clips', + 'video-clips-create' => 'episodes.manage-clips', + 'soundbites-list' => 'episodes.manage-clips', + 'soundbites-create' => 'episodes.manage-clips', + ], + 'count' => $episode->getClipCount(), + 'count-route' => 'video-clips-list', + 'add-cta' => 'video-clips-create', + ], +]; + +foreach (plugins()->getPluginsWithEpisodeSettings() as $plugin) { + $route = route_to('plugins-settings-episode', $plugin->getVendor(), $plugin->getPackage(), $podcast->id, $episode->id); + $episodeNavigation['plugins']['items'][] = $route; + $episodeNavigation['plugins']['items-labels'][$route] = $plugin->getTitle(); + $episodeNavigation['plugins']['items-permissions'][$route] = 'episodes.edit'; +} + +?> + + + 'mr-2', + ]) ?> + <?= esc($podcast->title) ?> + title) ?> + +
    + is_premium): ?> + 'absolute pl-1 text-xl rounded-r-full rounded-tl-lg left-4 top-4 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($episode->title) ?> + +
    + + $episodeNavigation, + 'langKey' => 'EpisodeNavigation', + 'podcastId' => $podcast->id, + 'episodeId' => $episode->id, +]) ?> diff --git a/themes/cp_admin/episode/create.php b/themes/cp_admin/episode/create.php new file mode 100644 index 00000000..bac39db6 --- /dev/null +++ b/themes/cp_admin/episode/create.php @@ -0,0 +1,212 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + +
    + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    +(' . + lang('Common.optional') . + ')' ?> +
    + /> + + + /> + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + + +
    +(' . + lang('Common.optional') . + ')' ?> +
    + /> + + + /> + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + + + + + + + + + + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/delete.php b/themes/cp_admin/episode/delete.php new file mode 100644 index 00000000..7121d222 --- /dev/null +++ b/themes/cp_admin/episode/delete.php @@ -0,0 +1,23 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/edit.php b/themes/cp_admin/episode/edit.php new file mode 100644 index 00000000..ab57b79d --- /dev/null +++ b/themes/cp_admin/episode/edit.php @@ -0,0 +1,292 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + + +
    + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    +(' . + lang('Common.optional') . + ')' ?> +
    + transcript_remote_url ? '' : 'checked' ?> /> + + + transcript_remote_url ? 'checked' : '' ?> /> + + +
    +
    + transcript) : ?> +
    + transcript->file_url, + icon('file-download-fill', [ + 'class' => 'mr-1 text-skin-muted text-xl', + ]) . lang('Episode.form.transcript_download'), + [ + 'class' => 'flex-1 font-semibold hover:underline inline-flex items-center text-xs', + 'download' => '', + ], + ) . + anchor( + route_to( + 'transcript-delete', + $podcast->id, + $episode->id, + ), + icon('delete-bin-fill', [ + 'class' => 'mx-auto', + ]), + [ + 'class' => 'p-1 text-sm bg-red-100 rounded-full text-red-700 hover:text-red-900', + 'data-tooltip' => 'bottom', + 'title' => lang( + 'Episode.form.transcript_file_delete', + ), + ], + ) ?> +
    + + + +
    +
    + + +
    +
    +
    +
    + + +
    +(' . + lang('Common.optional') . + ')' ?> +
    + chapters_remote_url ? '' : 'checked' ?> /> + + + chapters_remote_url ? 'checked' : '' ?> /> + + +
    +
    + chapters) : ?> +
    + chapters->file_url, + icon('file-download-fill', [ + 'class' => 'mr-1 text-skin-muted text-xl', + ]) . lang('Episode.form.chapters_download'), + [ + 'class' => 'flex-1 font-semibold hover:underline inline-flex items-center text-xs', + 'download' => '', + ], + ) . + anchor( + route_to( + 'chapters-delete', + $podcast->id, + $episode->id, + ), + icon('delete-bin-fill', [ + 'class' => 'mx-auto', + ]), + [ + 'class' => 'text-sm p-1 bg-red-100 rounded-full text-red-700 hover:text-red-900', + 'data-tooltip' => 'bottom', + 'title' => lang( + 'Episode.form.chapters_file_delete', + ), + ], + ) ?> +
    + + + +
    +
    + + +
    +
    +
    +
    +
    + + + + + + + +
    + +published_at === null): ?> + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/episode/embed.php b/themes/cp_admin/episode/embed.php new file mode 100644 index 00000000..d64e65e4 --- /dev/null +++ b/themes/cp_admin/episode/embed.php @@ -0,0 +1,43 @@ +height; + +?> + +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +

    + +
    + $theme): ?> + + +
    + + + +
    + embed_url}\">") ?>" /> + + +
    + +
    + + + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/list.php b/themes/cp_admin/episode/list.php new file mode 100644 index 00000000..7c6f6e80 --- /dev/null +++ b/themes/cp_admin/episode/list.php @@ -0,0 +1,173 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + +
    +

    + $pager->getDetails()['total'], + ]) ?>
    + $pager->getDetails()['currentPage'], + 'pageCount' => $pager->getDetails()['pageCount'], + ]) ?> +

    +
    + + 'text-xl', + ]) ?> +
    +
    + + lang('Episode.list.episode'), + 'cell' => function ($episode, $podcast) { + $premiumBadge = ''; + if ($episode->is_premium) { + $premiumBadge = icon('exchange-dollar-fill', [ + 'class' => 'absolute left-0 w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]); + } + + return ''; + }, + ], + [ + 'header' => lang('Episode.list.visibility'), + 'cell' => function ($episode): string { + return publication_pill( + $episode->published_at, + $episode->publication_status, + 'text-sm', + ); + }, + ], + [ + 'header' => lang('Episode.list.downloads'), + 'cell' => function ($episode): string { + return downloads_abbr($episode->downloads_count); + }, + ], + [ + 'header' => lang('Episode.list.comments'), + 'cell' => function ($episode): int { + return $episode->comments_count; + }, + ], + [ + 'header' => lang('Episode.list.actions'), + 'cell' => function ($episode, $podcast) { + $items = [ + [ + 'type' => 'link', + 'title' => lang('Episode.go_to_page'), + 'uri' => route_to('episode', esc($podcast->handle), esc($episode->slug)), + ], + [ + 'type' => 'link', + 'title' => lang('Episode.edit'), + 'uri' => route_to('episode-edit', $podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Episode.embed.title'), + 'uri' => route_to('embed-add', $podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Person.persons'), + 'uri' => route_to('episode-persons-manage', $podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('VideoClip.list.title'), + 'uri' => route_to('video-clips-list', $episode->podcast->id, $episode->id), + ], + [ + 'type' => 'link', + 'title' => lang('Soundbite.list.title'), + 'uri' => route_to('soundbites-list', $podcast->id, $episode->id), + ], + [ + 'type' => 'separator', + ], + ]; + if ($episode->published_at === null) { + $items[] = [ + 'type' => 'link', + 'title' => lang('Episode.delete'), + 'uri' => route_to('episode-delete', $podcast->id, $episode->id), + 'class' => 'font-semibold text-red-600', + ]; + } else { + $label = lang('Episode.delete'); + $icon = icon('forbid-fill'); + $title = lang('Episode.messages.unpublishBeforeDeleteTip'); + $items[] = [ + 'type' => 'html', + 'content' => esc(<<{$icon}{$label} + HTML), + ]; + } + return '' . + ''; + }, + ], + ], + $episodes, + 'mb-6 mt-4', + $podcast, +) ?> + +links() ?> + +endSection() ?> diff --git a/themes/cp_admin/episode/persons.php b/themes/cp_admin/episode/persons.php new file mode 100644 index 00000000..0a182c70 --- /dev/null +++ b/themes/cp_admin/episode/persons.php @@ -0,0 +1,94 @@ +extend('_layout') ?> + +section('pageTitle') ?> + (persons) ?>) +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + +
    + + + + + + + + + + + + +
    + + lang('Person.episode_form.persons'), + 'cell' => function ($person) { + return '
    ' . + '' . esc($person->full_name) . '' . + '
    ' . + esc($person->full_name) . + implode( + '', + array_map(function ($role) { + return '' . + lang( + "PersonsTaxonomy.persons.{$role->group}.label", + ) . + ' › ' . + lang( + "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", + ) . + ''; + }, $person->roles), + ) . + ($person->information_url === null + ? '' + : '' . + esc($person->information_url) . + '') . + '
    '; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($person): string { + // @icon("delete-bin-fill") + return '' . lang('Person.episode_form.remove') . ''; + }, + ], + ], + $episode->persons, + 'max-w-xl mt-6', +) ?> + +endSection() ?> diff --git a/themes/cp_admin/episode/publish.php b/themes/cp_admin/episode/publish.php new file mode 100644 index 00000000..c06d60cc --- /dev/null +++ b/themes/cp_admin/episode/publish.php @@ -0,0 +1,109 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +id, $episode->id), + icon('arrow-left-line', [ + 'class' => 'mr-2 text-lg', + ]) . lang('Episode.publish_form.back_to_episode_dashboard'), + [ + 'class' => 'inline-flex items-center font-semibold mr-4 text-sm', + ], +) ?> + +
    + + + + + +
    +
    + <?= esc($podcast->actor->display_name) ?> +
    +

    + actor->display_name) ?> + @actor->username) ?> +

    +
    +
    +
    + +
    + +
    + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 +
    +
    + +publication_status === 'published'): ?> +
    + + +
    + /> + +
    + +
    +
    +
    + + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/publish_date_edit.php b/themes/cp_admin/episode/publish_date_edit.php new file mode 100644 index 00000000..281f9f32 --- /dev/null +++ b/themes/cp_admin/episode/publish_date_edit.php @@ -0,0 +1,36 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +id, $episode->id), + icon('arrow-left-line', [ + 'class' => 'mr-2 text-lg', + ]) . lang('Episode.publish_form.back_to_episode_dashboard'), + [ + 'class' => 'inline-flex items-center font-semibold mr-4 text-sm', + ], +) ?> + +
    + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/episode/publish_edit.php b/themes/cp_admin/episode/publish_edit.php new file mode 100644 index 00000000..0d9ccf49 --- /dev/null +++ b/themes/cp_admin/episode/publish_edit.php @@ -0,0 +1,113 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +id, $episode->id), + icon('arrow-left-line', [ + 'class' => 'mr-2 text-lg', + ]) . lang('Episode.publish_form.back_to_episode_dashboard'), + [ + 'class' => 'inline-flex items-center font-semibold mr-4 text-sm', + ], +) ?> + +
    + + + + + + +
    +
    + <?= esc($podcast->actor->display_name) ?> +
    +

    + actor->display_name) ?> + @actor->username) ?> +

    + published_at, 'text-xs text-skin-muted') ?> +
    +
    +
    + +
    + +
    + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 +
    +
    + +publication_status === 'published'): ?> +
    + + +
    + /> + +
    + +
    +
    +
    + + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/soundbites_list.php b/themes/cp_admin/episode/soundbites_list.php new file mode 100644 index 00000000..bff27821 --- /dev/null +++ b/themes/cp_admin/episode/soundbites_list.php @@ -0,0 +1,45 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + + lang('Soundbite.list.soundbite'), + 'cell' => function ($soundbite): string { + return '
    ' . esc($soundbite->title) . '' . format_duration((int) $soundbite->duration) . '
    '; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($soundbite): string { + return '' . + ''; + }, + ], + ], + $soundbites, + 'mb-6', +) ?> + +links() ?> + +endSection() ?> diff --git a/themes/cp_admin/episode/soundbites_new.php b/themes/cp_admin/episode/soundbites_new.php new file mode 100644 index 00000000..a3114777 --- /dev/null +++ b/themes/cp_admin/episode/soundbites_new.php @@ -0,0 +1,32 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/episode/unpublish.php b/themes/cp_admin/episode/unpublish.php new file mode 100644 index 00000000..5d6d0048 --- /dev/null +++ b/themes/cp_admin/episode/unpublish.php @@ -0,0 +1,23 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/video_clip.php b/themes/cp_admin/episode/video_clip.php new file mode 100644 index 00000000..40dbebc6 --- /dev/null +++ b/themes/cp_admin/episode/video_clip.php @@ -0,0 +1,25 @@ +extend('_layout') ?> + +section('pageTitle') ?> + esc($videoClip->title), +]) ?> +endSection() ?> + +section('content') ?> + +media): ?> + + + +logs): ?> +
    + +
    logs ?>
    +
    + + +endSection() ?> diff --git a/themes/cp_admin/episode/video_clips_list.php b/themes/cp_admin/episode/video_clips_list.php new file mode 100644 index 00000000..b6fa6958 --- /dev/null +++ b/themes/cp_admin/episode/video_clips_list.php @@ -0,0 +1,135 @@ + +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + lang('VideoClip.list.status.label'), + 'cell' => function ($videoClip): string { + $pillVariantMap = [ + 'queued' => 'default', + 'pending' => 'warning', + 'running' => 'primary', + 'canceled' => 'default', + 'failed' => 'danger', + 'passed' => 'success', + ]; + + $pillIconMap = [ + 'queued' => 'timer-fill', // @icon("timer-fill") + 'pending' => 'pause-fill', // @icon("pause-fill") + 'running' => 'loader-fill', // @icon("loader-fill") + 'canceled' => 'forbid-fill', // @icon("forbid-fill") + 'failed' => 'close-fill', // @icon("close-fill") + 'passed' => 'check-fill', // @icon("check-fill") + ]; + + $pillIconClassMap = [ + 'queued' => '', + 'pending' => '', + 'running' => 'animate-spin', + 'canceled' => '', + 'failed' => '', + 'passed' => '', + ]; + + return '' . lang('VideoClip.list.status.' . $videoClip->status) . ''; + }, + ], + [ + 'header' => lang('VideoClip.list.clip'), + 'cell' => function ($videoClip): string { + $formatClass = [ + 'landscape' => 'aspect-video', + 'portrait' => 'aspect-[9/16]', + 'squared' => 'aspect-square', + ]; + return '
    ' . icon('play-fill') . '
    #' . $videoClip->id . ' – ' . esc($videoClip->title) . 'by ' . esc($videoClip->user->username) . '
    ' . format_duration((int) $videoClip->duration) . '
    '; + }, + ], + [ + 'header' => lang('VideoClip.list.duration'), + 'cell' => function (VideoClip $videoClip): string { + $duration = ''; + if ($videoClip->job_started_at !== null) { + if ($videoClip->job_ended_at !== null) { + $duration = '
    ' . + '
    ' . icon('timer-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . format_duration((int) $videoClip->job_duration, true) . '
    ' . + '
    ' . icon('calendar-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . relative_time($videoClip->job_ended_at) . '
    ' . + '
    '; + } else { + $duration = '
    ' . icon('timer-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . format_duration(($videoClip->job_started_at->difference(Time::now()))->getSeconds(), true) . '
    '; + } + } + + return $duration; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($videoClip): string { + $downloadButton = ''; + if ($videoClip->media) { + helper('misc'); + $filename = 'clip-' . slugify($videoClip->title) . "-{$videoClip->start_time}-{$videoClip->end_time}"; + // @icon("import-fill") + $downloadButton = '' . lang('VideoClip.download_clip') . ''; + } + + return '
    ' . $downloadButton . + '' . + '' . + '
    '; + }, + ], + ], + $videoClips, + 'mb-6', +) ?> + +links() ?> + +endSection() ?> diff --git a/themes/cp_admin/episode/video_clips_new.php b/themes/cp_admin/episode/video_clips_new.php new file mode 100644 index 00000000..24f0e1e9 --- /dev/null +++ b/themes/cp_admin/episode/video_clips_new.php @@ -0,0 +1,71 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + +
    + + <?= $episode->cover->description ?> + + + + + + +
    + +
    + + +
    + + + + +
    +
    + +
    + themes as $themeName => $colors): ?> + + +
    +
    +
    + + +
    +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/video_clips_requirements.php b/themes/cp_admin/episode/video_clips_requirements.php new file mode 100644 index 00000000..d1b41435 --- /dev/null +++ b/themes/cp_admin/episode/video_clips_requirements.php @@ -0,0 +1,31 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    +
    + 'flex-shrink-0 text-xl text-orange-600', + ]) ?> +

    +
    + $value): ?> + +
    'mr-1 text-white rounded-full bg-pine-500', + ]) ?>
    + +
    'mr-1 text-white bg-red-500 rounded-full', + ]) ?>
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/episode/view.php b/themes/cp_admin/episode/view.php new file mode 100644 index 00000000..c6392a36 --- /dev/null +++ b/themes/cp_admin/episode/view.php @@ -0,0 +1,60 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('headerLeft') ?> +published_at, + $episode->publication_status, + 'text-sm align-middle', +) ?> +endSection() ?> + +section('headerRight') ?> +publication_status === 'published'): ?> + + + +id, + $episode->id, + $episode->publication_status, +) ?> +endSection() ?> + + +section('content') ?> + +
    + audio->file_url, $episode->audio->file_mimetype) ?> +
    + +
    + + + +
    + + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/fediverse/blocked_actors.php b/themes/cp_admin/fediverse/blocked_actors.php new file mode 100644 index 00000000..7232de3d --- /dev/null +++ b/themes/cp_admin/fediverse/blocked_actors.php @@ -0,0 +1,49 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + lang('Fediverse.list.actor'), + 'cell' => function ($blockedActor) { + return esc($blockedActor->username); + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($blockedActor) { + return '
    ' . + '' . + csrf_field() . + '' . lang('Fediverse.list.unblock') . '' . + '
    '; + }, + ], + ], + $blockedActors, + 'mt-8', +) ?> + + +endSection() ?> diff --git a/themes/cp_admin/fediverse/blocked_domains.php b/themes/cp_admin/fediverse/blocked_domains.php new file mode 100644 index 00000000..51a2049b --- /dev/null +++ b/themes/cp_admin/fediverse/blocked_domains.php @@ -0,0 +1,47 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + lang('Fediverse.list.actor'), + 'cell' => function ($blockedDomain) { + return esc($blockedDomain->name); + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($blockedDomain) { + return '
    ' . + '' . + csrf_field() . + '' . lang('Fediverse.list.unblock') . '' . + '
    '; + }, + ], + ], + $blockedDomains, + 'mt-8', +) ?> + +endSection() ?> diff --git a/themes/cp_admin/import/_queue_table.php b/themes/cp_admin/import/_queue_table.php new file mode 100644 index 00000000..742fd10b --- /dev/null +++ b/themes/cp_admin/import/_queue_table.php @@ -0,0 +1,146 @@ + + + lang('PodcastImport.queue.status.label'), + 'cell' => function (PodcastImportTask $importTask) { + $pillVariantMap = [ + 'queued' => 'default', + 'pending' => 'warning', + 'running' => 'primary', + 'canceled' => 'default', + 'failed' => 'danger', + 'passed' => 'success', + ]; + + $pillIconMap = [ + 'queued' => 'timer-fill', // @icon("timer-fill") + 'pending' => 'pause-fill', // @icon("pause-fill") + 'running' => 'loader-fill', // @icon("loader-fill") + 'canceled' => 'forbid-fill', // @icon("forbid-fill") + 'failed' => 'close-fill', // @icon("close-fill") + 'passed' => 'check-fill', // @icon("check-fill") + ]; + + $pillIconClassMap = [ + 'queued' => '', + 'pending' => '', + 'running' => 'animate-spin', + 'canceled' => '', + 'failed' => '', + 'passed' => '', + ]; + + $errorHint = $importTask->status === TaskStatus::Failed ? '' . esc($importTask->error) . '' : ''; + + return '
    ' . lang('PodcastImport.queue.status.' . $importTask->status->value) . '' . $errorHint . '
    '; + }, + ], + [ + 'header' => lang('PodcastImport.queue.feed'), + 'cell' => function (PodcastImportTask $importTask) { + $externalLink = icon('external-link-fill', [ + 'class' => 'ml-1', + ]); + return << + {$importTask->feed_url}{$externalLink} + @{$importTask->handle} +
    + HTML; + }, + ], + [ + 'header' => lang('PodcastImport.queue.duration'), + 'cell' => function (PodcastImportTask $importTask) { + $duration = '-'; + if ($importTask->started_at !== null) { + if ($importTask->ended_at !== null) { + $duration = '
    ' . + '
    ' . icon('timer-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . format_duration((int) $importTask->getDuration(), true) . '
    ' . + '
    ' . icon('calendar-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . relative_time($importTask->ended_at) . '
    ' . + '
    '; + } else { + $duration = '
    ' . icon('timer-fill', [ + 'class' => 'text-sm text-gray-400', + ]) . format_duration(($importTask->started_at->difference(Time::now()))->getSeconds(), true) . '
    '; + } + } + + return $duration; + }, + ], + [ + 'header' => lang('PodcastImport.queue.imported_episodes'), + 'cell' => function (PodcastImportTask $importTask) { + if ($importTask->episodes_count) { + $progressPercentage = (int) ($importTask->getProgress() * 100) . '%'; + $moreInfoHelper = '' . lang('PodcastImport.queue.imported_episodes_hint', [ + 'newlyImportedCount' => $importTask->episodes_newly_imported, + 'alreadyImportedCount' => $importTask->episodes_already_imported, + ]) . ''; + return << + {$progressPercentage} +

    + {$importTask->episodes_imported} out of {$importTask->episodes_count} + {$moreInfoHelper} +

    +
    + HTML; + } + + return '-'; + }, + ], + [ + 'header' => lang('Common.list.actions'), + 'cell' => function (PodcastImportTask $importTask) { + $menuItems = [ + [ + 'type' => 'separator', + ], + [ + 'type' => 'link', + 'title' => lang('PodcastImport.queue.actions.delete'), + 'uri' => route_to('podcast-imports-task-action', $importTask->id, 'delete'), + 'class' => 'font-semibold text-red-600', + ], + ]; + + if ($importTask->status === TaskStatus::Running || $importTask->status === TaskStatus::Queued) { + array_unshift($menuItems, [ + 'type' => 'link', + 'title' => lang('PodcastImport.queue.actions.cancel'), + 'uri' => route_to('podcast-imports-task-action', $importTask->id, 'cancel'), + ]); + } else { + array_unshift($menuItems, [ + 'type' => 'link', + 'title' => lang('PodcastImport.queue.actions.retry'), + 'uri' => route_to('podcast-imports-task-action', $importTask->id, 'retry'), + ], ); + } + + return '
    ' . + '' . + '' . + '
    '; + }, + ], + ], + $podcastImportsQueue, +) ?> diff --git a/themes/cp_admin/import/add_to_queue.php b/themes/cp_admin/import/add_to_queue.php new file mode 100644 index 00000000..9a706bd7 --- /dev/null +++ b/themes/cp_admin/import/add_to_queue.php @@ -0,0 +1,61 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + + + + + + +
    + +
    + 'absolute inset-0 h-full text-xl opacity-40 left-3', + ]) ?> + +
    +
    + + + + + +
    + + + +
    + + +endSection() ?> diff --git a/themes/cp_admin/import/podcast_queue.php b/themes/cp_admin/import/podcast_queue.php new file mode 100644 index 00000000..a1aa7b6e --- /dev/null +++ b/themes/cp_admin/import/podcast_queue.php @@ -0,0 +1,16 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + +include('import/_queue_table'); ?> + +endSection() ?> diff --git a/themes/cp_admin/import/podcast_sync.php b/themes/cp_admin/import/podcast_sync.php new file mode 100644 index 00000000..5a57600e --- /dev/null +++ b/themes/cp_admin/import/podcast_sync.php @@ -0,0 +1,20 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> +
    + + + + + +endSection() ?> diff --git a/themes/cp_admin/import/queue.php b/themes/cp_admin/import/queue.php new file mode 100644 index 00000000..06c96968 --- /dev/null +++ b/themes/cp_admin/import/queue.php @@ -0,0 +1,17 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + +include('import/_queue_table'); ?> + +endSection() ?> diff --git a/themes/cp_admin/manifest.json b/themes/cp_admin/manifest.json new file mode 100644 index 00000000..6509e6a0 --- /dev/null +++ b/themes/cp_admin/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "Castopod Admin", + "description": "Castopod's default theme for admin" +} diff --git a/themes/cp_admin/my_account/change_password.php b/themes/cp_admin/my_account/change_password.php new file mode 100644 index 00000000..7c41193e --- /dev/null +++ b/themes/cp_admin/my_account/change_password.php @@ -0,0 +1,26 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + +endSection() ?> diff --git a/themes/cp_admin/my_account/view.php b/themes/cp_admin/my_account/view.php new file mode 100644 index 00000000..46ebb1c8 --- /dev/null +++ b/themes/cp_admin/my_account/view.php @@ -0,0 +1,15 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + + auth() + ->user(), +]) ?> + +endSection() ?> diff --git a/themes/cp_admin/page/create.php b/themes/cp_admin/page/create.php new file mode 100644 index 00000000..64789484 --- /dev/null +++ b/themes/cp_admin/page/create.php @@ -0,0 +1,39 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/page/edit.php b/themes/cp_admin/page/edit.php new file mode 100644 index 00000000..36b65daf --- /dev/null +++ b/themes/cp_admin/page/edit.php @@ -0,0 +1,43 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/page/list.php b/themes/cp_admin/page/list.php new file mode 100644 index 00000000..b03b5e20 --- /dev/null +++ b/themes/cp_admin/page/list.php @@ -0,0 +1,39 @@ +extend('_layout') ?> + +section('pageTitle') ?> + () +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + + lang('Page.page'), + 'cell' => function ($page) { + return '
    ' . + esc($page->title) . + '/' . + esc($page->slug) . + '
    '; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($page) { + return '' . lang('Page.go_to_page') . '' . + '' . lang('Page.edit') . '' . + '' . lang('Page.delete') . ''; + }, + ], + ], + $pages, +) ?> + +endSection() ?> diff --git a/themes/cp_admin/page/view.php b/themes/cp_admin/page/view.php new file mode 100644 index 00000000..74f001f1 --- /dev/null +++ b/themes/cp_admin/page/view.php @@ -0,0 +1,16 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> +
    + content_html ?> +
    +endSection() ?> diff --git a/themes/cp_admin/person/_card.php b/themes/cp_admin/person/_card.php new file mode 100644 index 00000000..b4506c8c --- /dev/null +++ b/themes/cp_admin/person/_card.php @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/themes/cp_admin/person/create.php b/themes/cp_admin/person/create.php new file mode 100644 index 00000000..d671f63f --- /dev/null +++ b/themes/cp_admin/person/create.php @@ -0,0 +1,42 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/person/edit.php b/themes/cp_admin/person/edit.php new file mode 100644 index 00000000..310f0f38 --- /dev/null +++ b/themes/cp_admin/person/edit.php @@ -0,0 +1,46 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/person/list.php b/themes/cp_admin/person/list.php new file mode 100644 index 00000000..01775d25 --- /dev/null +++ b/themes/cp_admin/person/list.php @@ -0,0 +1,26 @@ +extend('_layout') ?> + +section('pageTitle') ?> + () +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + + +
    + + $person, + ]) ?> + +
    + +

    + + +endSection() ?> diff --git a/themes/cp_admin/person/view.php b/themes/cp_admin/person/view.php new file mode 100644 index 00000000..b4ccc0d5 --- /dev/null +++ b/themes/cp_admin/person/view.php @@ -0,0 +1,28 @@ +extend('_layout') ?> + +section('pageTitle') ?> +full_name) ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + +
    + <?= esc($person->full_name) ?> +
    + full_name) ?> + information_url) ?> +
    +
    + +endSection() ?> diff --git a/themes/cp_admin/plugins/_plugin.php b/themes/cp_admin/plugins/_plugin.php new file mode 100644 index 00000000..66f94684 --- /dev/null +++ b/themes/cp_admin/plugins/_plugin.php @@ -0,0 +1,85 @@ + +
    +
    + getStatus() === PluginStatus::ACTIVE): ?> + + + getStatus() === PluginStatus::INACTIVE): ?> + + + getStatus() === PluginStatus::INVALID): ?> + + + getStatus() === PluginStatus::INCOMPATIBLE): ?> + + + +
    + +
    +

    getTitle() ?>

    +

    + + getVendor() ?> + / + getPackage() ?> + getVersion() ?> +

    +

    getDescription() ?? '' . lang('Plugins.noDescription') . '' ?>

    +
    +
    +
    + getHomepage()): ?> + + + + getRepository()): ?> + + + +
    +
    + getStatus() === PluginStatus::ACTIVE): ?> +
    + + +
    + getStatus() === PluginStatus::INACTIVE): ?> +
    + + +
    + + getSettingsFields('general') !== []): ?> + + + + + 'link', + 'title' => lang('Plugins.view'), + 'uri' => route_to('plugins-view', $plugin->getVendor(), $plugin->getPackage()), + ], + [ + 'type' => 'separator', + ], + [ + 'type' => 'link', + 'title' => icon('delete-bin-fill', [ + 'class' => 'text-gray-500', + ]) . lang('Plugins.uninstall'), + 'uri' => route_to('plugins-uninstall', $plugin->getVendor(), $plugin->getPackage()), + 'class' => 'font-semibold text-red-600', + ], + ]; ?> + +
    +
    +
    \ No newline at end of file diff --git a/themes/cp_admin/plugins/_settings_form.php b/themes/cp_admin/plugins/_settings_form.php new file mode 100644 index 00000000..0da038ad --- /dev/null +++ b/themes/cp_admin/plugins/_settings_form.php @@ -0,0 +1,61 @@ +
    + + + + type === 'datetime') { + $hasDatetime = true; + } ?> + multiple): + if ($field->type === 'group'): ?> +
    +
    + label ?> + getKey(), $field->key, $context) ?? ['']; + foreach ($fieldArrayValues as $index => $value): ?> +
    + label ?> + fields as $subfield): ?> + render(sprintf('%s[%s][%s]', $field->key, $index, $subfield->key), $value[$subfield->key] ?? null, 'flex-1'); ?> + + +
    + +
    + +
    + +
    +
    + getKey(), $field->key, $context) ?? ['']; + foreach ($fieldArrayValue as $index => $value): ?> +
    + + render(sprintf('%s[%s]', $field->key, $index), $value, 'flex-1'); ?> + +
    + +
    + +
    + + type === 'group'): + $value = get_plugin_setting($plugin->getKey(), $field->key, $context); ?> +
    + label ?> + fields as $subfield): ?> + render(sprintf('%s[%s]', $field->key, $subfield->key), $value[$subfield->key] ?? null, 'flex-1'); ?> + +
    + + render($field->key, get_plugin_setting($plugin->getKey(), $field->key, $context)); ?> + + + + + + + + +
    + diff --git a/themes/cp_admin/plugins/installed.php b/themes/cp_admin/plugins/installed.php new file mode 100644 index 00000000..3e5735cd --- /dev/null +++ b/themes/cp_admin/plugins/installed.php @@ -0,0 +1,16 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> +
    + $plugin, + ]); +} ?> +
    + +endSection() ?> diff --git a/themes/cp_admin/plugins/settings.php b/themes/cp_admin/plugins/settings.php new file mode 100644 index 00000000..c317c8b4 --- /dev/null +++ b/themes/cp_admin/plugins/settings.php @@ -0,0 +1,33 @@ +extend('_layout') ?> + +section('pageTitle') ?> + $plugin->getTitle(), + 'type' => $type, +]) ?> +endSection() ?> + +getVendor(), + $plugin->getPackage(), + ]; + +if (isset($podcast)) { + $params[] = $podcast->id; +} + +if (isset($episode)) { + $params[] = $episode->id; +} +?> + +section('content') ?> + $plugin, + 'action' => route_to(sprintf('plugins-settings-%s-action', $type), ...$params), + 'fields' => $fields, + 'type' => $type, + 'context' => $context, +]) ?> +endSection() ?> diff --git a/themes/cp_admin/plugins/view.php b/themes/cp_admin/plugins/view.php new file mode 100644 index 00000000..1f054505 --- /dev/null +++ b/themes/cp_admin/plugins/view.php @@ -0,0 +1,143 @@ + + +extend('_layout') ?> + +section('pageTitle') ?> +getTitle() ?> +endSection() ?> + +section('headerLeft') ?> +getStatus() === PluginStatus::ACTIVE): ?> + + +getStatus() === PluginStatus::INACTIVE): ?> + + +getStatus() === PluginStatus::INVALID): ?> + + + +endSection() ?> + +section('headerRight') ?> +getStatus() === PluginStatus::ACTIVE): ?> +
    + + + getSettingsFields('general') !== []): ?> + + + +
    +getStatus() === PluginStatus::INVALID): ?> +
    + + + getSettingsFields('general') !== []): ?> + + + +
    + +endSection() ?> + +section('content') ?> +getStatus() === PluginStatus::INVALID): ?> + +
      + getErrors() as $key => $error): ?> +
    • + +
    +
    + + +
    + + + 'icon', + ]) ?>README.md + getReadmeHTML()): ?> + + getReadmeHTML() ?> + + + +
    + 'text-gray-300 text-6xl', + ]) ?> +

    +
    +
    + + getLicenseHTML()): ?> + 'icon', + ]) ?>LICENSE.md + + getLicenseHTML() ?> + + +
    +
    +endSection() ?> \ No newline at end of file diff --git a/themes/cp_admin/podcast/_card.php b/themes/cp_admin/podcast/_card.php new file mode 100644 index 00000000..93d2f4f2 --- /dev/null +++ b/themes/cp_admin/podcast/_card.php @@ -0,0 +1,55 @@ + diff --git a/themes/cp_admin/podcast/_platform.php b/themes/cp_admin/podcast/_platform.php new file mode 100644 index 00000000..d0a56dee --- /dev/null +++ b/themes/cp_admin/podcast/_platform.php @@ -0,0 +1,64 @@ + diff --git a/themes/cp_admin/podcast/_sidebar.php b/themes/cp_admin/podcast/_sidebar.php new file mode 100644 index 00000000..a6967cb3 --- /dev/null +++ b/themes/cp_admin/podcast/_sidebar.php @@ -0,0 +1,144 @@ + [ + 'icon' => 'dashboard-fill', // @icon("dashboard-fill") + 'items' => ['podcast-view', 'podcast-edit', 'podcast-persons-manage', 'podcast-imports', 'podcast-imports-sync'], + 'items-permissions' => [ + 'podcast-view' => 'view', + 'podcast-edit' => 'edit', + 'podcast-persons-manage' => 'manage-persons', + 'podcast-imports' => 'manage-import', + 'podcast-imports-sync' => 'manage-import', + ], + ], + 'episodes' => [ + 'icon' => 'play-circle-fill', // @icon("play-circle-fill") + 'items' => ['episode-list', 'episode-create'], + 'items-permissions' => [ + 'episode-list' => 'episodes.view', + 'episode-create' => 'episodes.create', + ], + 'add-cta' => 'episode-create', + 'count' => $podcast->getEpisodesCount(), + 'count-route' => 'episode-list', + ], + 'plugins' => [ + 'icon' => 'puzzle-fill', // @icon("puzzle-fill") + 'items' => [], + 'items-labels' => [], + 'items-permissions' => [], + ], + 'analytics' => [ + 'icon' => 'line-chart-fill', // @icon("line-chart-fill") + 'items' => [ + 'podcast-analytics', + 'podcast-analytics-unique-listeners', + 'podcast-analytics-listening-time', + 'podcast-analytics-players', + 'podcast-analytics-locations', + 'podcast-analytics-time-periods', + 'podcast-analytics-webpages', + ], + 'items-permissions' => [ + 'podcast-analytics' => 'view', + 'podcast-analytics-unique-listeners' => 'view', + 'podcast-analytics-listening-time' => 'view', + 'podcast-analytics-players' => 'view', + 'podcast-analytics-locations' => 'view', + 'podcast-analytics-time-periods' => 'view', + 'podcast-analytics-webpages' => 'view', + ], + ], + 'broadcast' => [ + 'icon' => 'broadcast-fill', // @icon("broadcast-fill") + 'items' => [ + 'platforms-podcasting', + 'platforms-social', + ], + 'items-permissions' => [ + 'platforms-podcasting' => 'manage-platforms', + 'platforms-social' => 'manage-platforms', + ], + ], + 'monetization' => [ + 'icon' => 'money-dollar-circle-fill', // @icon("money-dollar-circle-fill") + 'items' => [ + 'subscription-list', + 'subscription-create', + 'platforms-funding', + ], + 'items-permissions' => [ + 'subscription-list' => 'manage-subscriptions', + 'subscription-create' => 'manage-subscriptions', + 'platforms-funding' => 'manage-platforms', + ], + ], + 'contributors' => [ + 'icon' => 'group-fill', // @icon("group-fill") + 'items' => ['contributor-list', 'contributor-add'], + 'items-permissions' => [ + 'contributor-list' => 'manage-contributors', + 'contributor-add' => 'manage-contributors', + ], + 'add-cta' => 'contributor-add', + 'count' => count($podcast->contributors), + 'count-route' => 'contributor-list', + ], +]; + +foreach (plugins()->getPluginsWithPodcastSettings() as $plugin) { + $route = route_to('plugins-settings-podcast', $plugin->getVendor(), $plugin->getPackage(), $podcast->id); + $podcastNavigation['plugins']['items'][] = $route; + $podcastNavigation['plugins']['items-labels'][$route] = $plugin->getTitle(); + $podcastNavigation['plugins']['items-permissions'][$route] = 'edit'; +} + +?> + +
    +
    + is_premium): ?> + 'absolute left-0 pl-1 text-xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($podcast->title) ?> +
    + +
    + + $podcastNavigation, + 'langKey' => 'PodcastNavigation', + 'podcastId' => $podcast->id, +]) ?> diff --git a/themes/cp_admin/podcast/analytics/index.php b/themes/cp_admin/podcast/analytics/index.php new file mode 100644 index 00000000..9407f828 --- /dev/null +++ b/themes/cp_admin/podcast/analytics/index.php @@ -0,0 +1,34 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + + + +
    + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/listening_time.php b/themes/cp_admin/podcast/analytics/listening_time.php new file mode 100644 index 00000000..aa70fdcd --- /dev/null +++ b/themes/cp_admin/podcast/analytics/listening_time.php @@ -0,0 +1,27 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + +
    + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/locations.php b/themes/cp_admin/podcast/analytics/locations.php new file mode 100644 index 00000000..da24a3dc --- /dev/null +++ b/themes/cp_admin/podcast/analytics/locations.php @@ -0,0 +1,32 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + +
    + + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/players.php b/themes/cp_admin/podcast/analytics/players.php new file mode 100644 index 00000000..4740689c --- /dev/null +++ b/themes/cp_admin/podcast/analytics/players.php @@ -0,0 +1,44 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + + + +
    + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/time_periods.php b/themes/cp_admin/podcast/analytics/time_periods.php new file mode 100644 index 00000000..4a2e9ef0 --- /dev/null +++ b/themes/cp_admin/podcast/analytics/time_periods.php @@ -0,0 +1,25 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + +
    + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/unique_listeners.php b/themes/cp_admin/podcast/analytics/unique_listeners.php new file mode 100644 index 00000000..935f1961 --- /dev/null +++ b/themes/cp_admin/podcast/analytics/unique_listeners.php @@ -0,0 +1,27 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + +
    + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/analytics/webpages.php b/themes/cp_admin/podcast/analytics/webpages.php new file mode 100644 index 00000000..23877595 --- /dev/null +++ b/themes/cp_admin/podcast/analytics/webpages.php @@ -0,0 +1,38 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('content') ?> + +
    + + + + +
    + + + +asset('js/charts.ts', 'js') ?> +endSection() ?> diff --git a/themes/cp_admin/podcast/create.php b/themes/cp_admin/podcast/create.php new file mode 100644 index 00000000..e27e2700 --- /dev/null +++ b/themes/cp_admin/podcast/create.php @@ -0,0 +1,187 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + 'absolute inset-0 h-full text-xl opacity-40 left-3', + ]) ?> + +
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/delete.php b/themes/cp_admin/podcast/delete.php new file mode 100644 index 00000000..9984c0c5 --- /dev/null +++ b/themes/cp_admin/podcast/delete.php @@ -0,0 +1,23 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/edit.php b/themes/cp_admin/podcast/edit.php new file mode 100644 index 00000000..aed8fe82 --- /dev/null +++ b/themes/cp_admin/podcast/edit.php @@ -0,0 +1,237 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + +endSection() ?> + +section('content') ?> + +
    + + + +
    + banner_id !== null): ?> + + + +
    + <?= esc($podcast->title) ?> +
    +

    title) ?>

    +

    @handle) ?>

    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + 'absolute inset-0 h-full text-xl opacity-40 left-3', + ]) ?> + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + +
    + +
    + + + +endSection() ?> diff --git a/themes/cp_admin/podcast/latest_episodes.php b/themes/cp_admin/podcast/latest_episodes.php new file mode 100644 index 00000000..d51926dc --- /dev/null +++ b/themes/cp_admin/podcast/latest_episodes.php @@ -0,0 +1,25 @@ +
    +
    + + + + 'ml-2', + ]) ?> + +
    + +
    + + $episode, + ]) ?> + +
    + +

    + +
    diff --git a/themes/cp_admin/podcast/list.php b/themes/cp_admin/podcast/list.php new file mode 100644 index 00000000..5fc2a6cb --- /dev/null +++ b/themes/cp_admin/podcast/list.php @@ -0,0 +1,31 @@ +extend('_layout') ?> + +section('pageTitle') ?> + () +endSection() ?> + +section('headerRight') ?> + + + +endSection() ?> + + +section('content') ?> + +
    + + + $podcast, + ]) ?> + + +

    + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/notifications.php b/themes/cp_admin/podcast/notifications.php new file mode 100644 index 00000000..336b2680 --- /dev/null +++ b/themes/cp_admin/podcast/notifications.php @@ -0,0 +1,107 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + +endSection() ?> + +section('content') ?> + +
    + +
    + read_at === null ? 'bg-heading-background' : 'bg-base'; + ?> +
    + post_id !== null ? $notification->post : null; + + $actorUsername = '@' . esc($notification->actor + ->username) . + ($notification->actor->is_local + ? '' + : '@' . esc($notification->actor->domain)); + + $actorUsernameHtml = <<{$actorUsername} + HTML; + + $targetActorUsername = '@' . esc($notification->target_actor->username); + + $targetActorUsernameHtml = <<{$targetActorUsername} + HTML; + + $notificationTitle = match ($notification->type) { + 'reply' => lang('Notifications.reply', [ + 'actor_username' => $actorUsernameHtml, + ], null, false), + 'like' => lang('Notifications.favourite', [ + 'actor_username' => $actorUsernameHtml, + ], null, false), + 'share' => lang('Notifications.reblog', [ + 'actor_username' => $actorUsernameHtml, + ], null, false), + 'follow' => lang('Notifications.follow', [ + 'actor_username' => $actorUsernameHtml, + ], null, false), + default => '', + }; + $notificationContent = $post !== null ? $post->message_html : null; + + $postLink = $post !== null ? route_to('post', esc($podcast->handle), $post->id) : route_to('podcast-activity', esc($podcast->handle)); + $link = $notification->read_at !== null ? $postLink : route_to('notification-mark-as-read', $podcast->id, $notification->id); + ?> + +
    +
    + +
    + <?= esc($notification->actor->display_name) ?> + + type) { + 'reply' => icon('chat-4-fill', [ + 'class' => 'text-sky-500 text-base', + ]), + 'like' => icon('heart-fill', [ + 'class' => 'text-rose-500 text-base', + ]), + 'share' => icon('repeat-fill', [ + 'class' => 'text-green-500 text-base', + ]), + 'follow' => icon('user-follow-fill', [ + 'class' => 'text-violet-500 text-base', + ]), + default => '', + }; + ?> + + +
    +
    +
    +
    + + +

    + +
    + created_at) ?> +
    +
    +
    +
    + +
    + +
    links() ?>
    + + + +endsection() ?> diff --git a/themes/cp_admin/podcast/persons.php b/themes/cp_admin/podcast/persons.php new file mode 100644 index 00000000..a14745b8 --- /dev/null +++ b/themes/cp_admin/podcast/persons.php @@ -0,0 +1,92 @@ +extend('_layout') ?> + +section('pageTitle') ?> + (persons) ?>) +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + +section('content') ?> + +
    + + + + + + + + + + + +
    + + lang('Person.podcast_form.persons'), + 'cell' => function ($person) { + return '
    ' . + '' . esc($person->full_name) . '' . + '
    ' . + esc($person->full_name) . + implode( + '', + array_map(function ($role) { + return '' . + lang( + "PersonsTaxonomy.persons.{$role->group}.label", + ) . + ' › ' . + lang( + "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label", + ) . + ''; + }, $person->roles), + ) . + ($person->information_url === null + ? '' + : '' . + esc($person->information_url) . + '') . + '
    '; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($person): string { + // @icon("delete-bin-fill") + return '' . lang('Person.podcast_form.remove') . ''; + }, + ], + ], + $podcast->persons, + 'max-w-xl mt-6', +) ?> + +endSection() ?> \ No newline at end of file diff --git a/themes/cp_admin/podcast/platforms.php b/themes/cp_admin/podcast/platforms.php new file mode 100644 index 00000000..d86f2f52 --- /dev/null +++ b/themes/cp_admin/podcast/platforms.php @@ -0,0 +1,25 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + +endSection() ?> + +section('content') ?> + +
    + + + + $platform, + ]); +} ?> + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/publish.php b/themes/cp_admin/podcast/publish.php new file mode 100644 index 00000000..f1b91617 --- /dev/null +++ b/themes/cp_admin/podcast/publish.php @@ -0,0 +1,84 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +id), + icon('arrow-left-line', [ + 'class' => 'mr-2 text-lg', + ]) . lang('Podcast.publish_form.back_to_podcast_dashboard'), + [ + 'class' => 'inline-flex items-center font-semibold mr-4 text-sm', + ], +) ?> + +
    + + + + + +
    +
    + <?= esc($podcast->actor->display_name) ?> +
    +

    + actor->display_name) ?> + @actor->username) ?> +

    +
    +
    +
    + +
    +
    + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 +
    +
    + +
    + + +
    + /> + +
    + +
    +
    +
    + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/publish_edit.php b/themes/cp_admin/podcast/publish_edit.php new file mode 100644 index 00000000..4dd40dc8 --- /dev/null +++ b/themes/cp_admin/podcast/publish_edit.php @@ -0,0 +1,85 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +id), + icon('arrow-left-line', [ + 'class' => 'mr-2 text-lg', + ]) . lang('Podcast.publish_form.back_to_podcast_dashboard'), + [ + 'class' => 'inline-flex items-center font-semibold mr-4 text-sm', + ], +) ?> + +
    + + + + + +
    +
    + <?= esc($podcast->actor->display_name) ?> +
    +

    + actor->display_name) ?> + @actor->username) ?> +

    + published_at, 'text-xs text-skin-muted') ?> +
    +
    +
    + +
    +
    + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 + 'mr-1 text-xl opacity-40', + ]) ?>0 +
    +
    + +
    + + +
    + /> + +
    + +
    +
    +
    + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/podcast/settings/dashboard.php b/themes/cp_admin/podcast/settings/dashboard.php new file mode 100644 index 00000000..9129f398 --- /dev/null +++ b/themes/cp_admin/podcast/settings/dashboard.php @@ -0,0 +1,9 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> +Podcast settings... +endSection() ?> diff --git a/themes/cp_admin/podcast/view.php b/themes/cp_admin/podcast/view.php new file mode 100644 index 00000000..7d54cbb7 --- /dev/null +++ b/themes/cp_admin/podcast/view.php @@ -0,0 +1,23 @@ +extend('_layout') ?> + +section('pageTitle') ?> +title) ?> +endSection() ?> + +section('headerRight') ?> + + + +endSection() ?> + +section('content') ?> + + 5, + 'podcastId' => $podcast->id, +]) ?> + +endSection() ?> diff --git a/themes/cp_admin/settings/about.php b/themes/cp_admin/settings/about.php new file mode 100644 index 00000000..9f9b15fd --- /dev/null +++ b/themes/cp_admin/settings/about.php @@ -0,0 +1,35 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + +
    + + $value): ?> +
    +
    + +
    +
    + +
    +
    + + +endSection() ?> diff --git a/themes/cp_admin/settings/general.php b/themes/cp_admin/settings/general.php new file mode 100644 index 00000000..f82ede6e --- /dev/null +++ b/themes/cp_admin/settings/general.php @@ -0,0 +1,88 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> +
    + +
    + + + + + + + + +
    + + siteIcon['ico'] !== service('settings')->get('App.siteIcon')['ico']): ?> +
    + + <?= esc(service('settings')->get('App.siteName')) ?> Favicon +
    + +
    + + + +
    + +
    + +
    + + + + + + + + +
    + +
    + + + + + + + + + + + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/settings/theme.php b/themes/cp_admin/settings/theme.php new file mode 100644 index 00000000..e0b0612f --- /dev/null +++ b/themes/cp_admin/settings/theme.php @@ -0,0 +1,31 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + +
    + themes as $themeName => $color): ?> + + +
    + + + +
    + +
    +endSection() ?> \ No newline at end of file diff --git a/themes/cp_admin/subscription/create.php b/themes/cp_admin/subscription/create.php new file mode 100644 index 00000000..31a73a22 --- /dev/null +++ b/themes/cp_admin/subscription/create.php @@ -0,0 +1,31 @@ +extend('../cp_admin/_layout') ?> + +section('pageTitle') ?> +title)]) ?> +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/subscription/delete.php b/themes/cp_admin/subscription/delete.php new file mode 100644 index 00000000..d71644ed --- /dev/null +++ b/themes/cp_admin/subscription/delete.php @@ -0,0 +1,25 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + $subscription->email, +]) ?> + + + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/subscription/edit.php b/themes/cp_admin/subscription/edit.php new file mode 100644 index 00000000..a5ef6ca8 --- /dev/null +++ b/themes/cp_admin/subscription/edit.php @@ -0,0 +1,35 @@ +extend('../cp_admin/_layout') ?> + +section('pageTitle') ?> +title)]) ?> +endSection() ?> + + +section('content') ?> + +
    + + + +
    +
    + +
    +
    + email) ?> +
    +
    + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/subscription/email/_credentials_list.php b/themes/cp_admin/subscription/email/_credentials_list.php new file mode 100644 index 00000000..1e7460c3 --- /dev/null +++ b/themes/cp_admin/subscription/email/_credentials_list.php @@ -0,0 +1,4 @@ +
      +
    • ' . $token . ''], $subscription->podcast->language_code, false) ?>
    • +
    • podcast->feedUrl . '?token=' . $token . '">' . $subscription->podcast->feedUrl . '?token=' . $token . ''], $subscription->podcast->language_code, false) ?>
    • +
    diff --git a/themes/cp_admin/subscription/email/_footer.php b/themes/cp_admin/subscription/email/_footer.php new file mode 100644 index 00000000..39aef516 --- /dev/null +++ b/themes/cp_admin/subscription/email/_footer.php @@ -0,0 +1,6 @@ +

    ---
    + + 'Castopod', + 'host' => '' . current_domain() . '', +], $subscription->podcast->language_code, false) ?> diff --git a/themes/cp_admin/subscription/email/_how_to_use.php b/themes/cp_admin/subscription/email/_how_to_use.php new file mode 100644 index 00000000..04ddb480 --- /dev/null +++ b/themes/cp_admin/subscription/email/_how_to_use.php @@ -0,0 +1,8 @@ +

    podcast->language_code) ?>

    +

    podcast->language_code) ?>

    +
      +
    1. podcast->language_code) ?>
    2. +
    3. '' . $subscription->podcast->title . '', + ], $subscription->podcast->language_code, false) ?>
    4. +
    diff --git a/themes/cp_admin/subscription/email/deleted.php b/themes/cp_admin/subscription/email/deleted.php new file mode 100644 index 00000000..093b6156 --- /dev/null +++ b/themes/cp_admin/subscription/email/deleted.php @@ -0,0 +1,7 @@ +podcast->language_code) ?>

    + + '' . $subscription->podcast->title . '', +], $subscription->podcast->language_code, false) ?> + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/email/edited.php b/themes/cp_admin/subscription/email/edited.php new file mode 100644 index 00000000..a1826019 --- /dev/null +++ b/themes/cp_admin/subscription/email/edited.php @@ -0,0 +1,18 @@ +podcast->language_code) ?>

    + +expires_at): ?> + podcast->language_code, IntlDateFormatter::LONG, IntlDateFormatter::LONG); + $translatedDate = $subscription->expires_at->toLocalizedString($formatter->getPattern()); + ?> + '' . $subscription->podcast->title . '', + 'expiresAt' => '' . $translatedDate . '', + ], $subscription->podcast->language_code, false) ?> + + '' . $subscription->podcast->title . '', + ], $subscription->podcast->language_code, false) ?> + + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/email/reset.php b/themes/cp_admin/subscription/email/reset.php new file mode 100644 index 00000000..dea6449f --- /dev/null +++ b/themes/cp_admin/subscription/email/reset.php @@ -0,0 +1,13 @@ +podcast->language_code) ?>

    + + '' . $subscription->podcast->title . '', +], $subscription->podcast->language_code, false) ?>

    + +podcast->language_code) ?> + +include('subscription/email/_credentials_list') ?> + +include('subscription/email/_how_to_use') ?> + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/email/resumed.php b/themes/cp_admin/subscription/email/resumed.php new file mode 100644 index 00000000..f06f08a4 --- /dev/null +++ b/themes/cp_admin/subscription/email/resumed.php @@ -0,0 +1,7 @@ +podcast->language_code) ?>

    + + '' . $subscription->podcast->title . '', +], $subscription->podcast->language_code, false) ?> + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/email/suspended.php b/themes/cp_admin/subscription/email/suspended.php new file mode 100644 index 00000000..e59a34e0 --- /dev/null +++ b/themes/cp_admin/subscription/email/suspended.php @@ -0,0 +1,11 @@ +podcast->language_code) ?>

    + + '' . $subscription->podcast->title . '', +], $subscription->podcast->language_code, false) ?>

    + +status_message): ?> +
    ' . nl2br($subscription->status_message) . ''], $subscription->podcast->language_code, false) ?> + + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/email/welcome.php b/themes/cp_admin/subscription/email/welcome.php new file mode 100644 index 00000000..73b5fc32 --- /dev/null +++ b/themes/cp_admin/subscription/email/welcome.php @@ -0,0 +1,23 @@ +podcast->language_code) ?>

    + + '' . $subscription->podcast->title . '', +], $subscription->podcast->language_code, false) ?>

    + +podcast->language_code) ?> + +include('subscription/email/_credentials_list') ?> + +expires_at): ?> + podcast->language_code, IntlDateFormatter::LONG, IntlDateFormatter::LONG); + $translatedDate = $subscription->expires_at->toLocalizedString($formatter->getPattern()); + ?> + ' . $translatedDate . ''], $subscription->podcast->language_code, false) ?> + + podcast->language_code) ?> + + +include('subscription/email/_how_to_use') ?> + +include('subscription/email/_footer') ?> diff --git a/themes/cp_admin/subscription/list.php b/themes/cp_admin/subscription/list.php new file mode 100644 index 00000000..6b9f09ae --- /dev/null +++ b/themes/cp_admin/subscription/list.php @@ -0,0 +1,127 @@ +extend('../cp_admin/_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + +
    + + + + + +
    + + lang('Subscription.list.number'), + 'cell' => function ($subscription) { + return '#' . $subscription->id; + }, + ], + [ + 'header' => lang('Subscription.list.email'), + 'cell' => function ($subscription) { + return esc($subscription->email); + }, + ], + [ + 'header' => lang('Subscription.list.expiration_date'), + 'cell' => function ($subscription) { + return $subscription->expires_at ? local_date($subscription->expires_at) : lang('Subscription.list.unlimited'); + }, + ], + [ + 'header' => lang('Subscription.list.downloads'), + 'cell' => function ($subscription) { + return $subscription->downloads_last_3_months; + }, + ], + [ + 'header' => lang('Subscription.list.status'), + 'cell' => function ($subscription) { + $statusMapping = [ + 'active' => 'success', + 'suspended' => 'warning', + 'expired' => 'default', + ]; + + return '' . lang('Subscription.status.' . $subscription->status) . ''; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($subscription, $podcast) { + $items = [ + [ + 'type' => 'link', + 'title' => lang('Subscription.view'), + 'uri' => route_to('subscription-view', $podcast->id, $subscription->id), + ], + [ + 'type' => 'link', + 'title' => lang('Subscription.edit'), + 'uri' => route_to('subscription-edit', $podcast->id, $subscription->id), + ], + [ + 'type' => 'link', + 'title' => lang('Subscription.regenerate_token'), + 'uri' => route_to('subscription-regenerate-token', $podcast->id, $subscription->id), + ], + [ + 'type' => 'separator', + ], + [ + 'type' => 'link', + 'title' => lang('Subscription.delete'), + 'uri' => route_to('subscription-delete', $podcast->id, $subscription->id), + 'class' => 'font-semibold text-red-600', + ], + ]; + + if ($subscription->status === 'suspended') { + $suspendAction = [[ + 'type' => 'link', + 'title' => lang('Subscription.resume'), + 'uri' => route_to('subscription-resume', $podcast->id, $subscription->id), + ]]; + } else { + $suspendAction = [[ + 'type' => 'link', + 'title' => lang('Subscription.suspend'), + 'uri' => route_to('subscription-suspend', $podcast->id, $subscription->id), + ]]; + } + + array_splice($items, 3, 0, $suspendAction); + + return '' . + ''; + }, + ], + ], + $podcast->subscriptions, + '', + $podcast, +) ?> + +endSection() ?> diff --git a/themes/cp_admin/subscription/suspend.php b/themes/cp_admin/subscription/suspend.php new file mode 100644 index 00000000..6df03d74 --- /dev/null +++ b/themes/cp_admin/subscription/suspend.php @@ -0,0 +1,33 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> + +
    + + + $subscription->email, +]) ?> + + + +
    + + + +
    + + + +endSection() ?> diff --git a/themes/cp_admin/subscription/view.php b/themes/cp_admin/subscription/view.php new file mode 100644 index 00000000..9111b95a --- /dev/null +++ b/themes/cp_admin/subscription/view.php @@ -0,0 +1,13 @@ +extend('../cp_admin/_layout') ?> + +section('pageTitle') ?> +id), +]) ?> +endSection() ?> + +section('content') ?> + +email ?> + +endSection() ?> diff --git a/themes/cp_admin/user/create.php b/themes/cp_admin/user/create.php new file mode 100644 index 00000000..4cc5a9f2 --- /dev/null +++ b/themes/cp_admin/user/create.php @@ -0,0 +1,36 @@ +extend('_layout') ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/user/delete.php b/themes/cp_admin/user/delete.php new file mode 100644 index 00000000..5bebfb4d --- /dev/null +++ b/themes/cp_admin/user/delete.php @@ -0,0 +1,29 @@ +extend('_layout') ?> + +section('pageTitle') ?> + $user->username, +]) ?> +endSection() ?> + +section('content') ?> + +
    + + + $user->username, +]) ?> + + $user->username, +]) ?> + +
    + + +
    + +
    + +endSection() ?> diff --git a/themes/cp_admin/user/edit.php b/themes/cp_admin/user/edit.php new file mode 100644 index 00000000..8631088e --- /dev/null +++ b/themes/cp_admin/user/edit.php @@ -0,0 +1,27 @@ +extend('_layout') ?> + +section('pageTitle') ?> + esc($user->username), +]) ?> +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + +endSection() ?> diff --git a/themes/cp_admin/user/list.php b/themes/cp_admin/user/list.php new file mode 100644 index 00000000..457c594e --- /dev/null +++ b/themes/cp_admin/user/list.php @@ -0,0 +1,60 @@ +extend('_layout') ?> + +section('pageTitle') ?> + () +endSection() ?> + +section('headerRight') ?> + + +endSection() ?> + + +section('content') ?> + + lang('User.list.user'), + 'cell' => function ($user) { + return '
    ' . + esc($user->username) . + '' . + $user->email . + '
    '; + }, + ], + [ + 'header' => lang('User.list.role'), + 'cell' => function ($user) { + $role = get_group_info(get_instance_group($user))['title']; + + if ((bool) $user->is_owner) { + $role = '
    ' . icon('shield-user-fill') . '' . $role . '
    '; + } + + // @icon("pencil-fill") + return $role . '' . lang('User.edit_role', [ + 'username' => esc($user->username), + ]) . ''; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($user) { + return '' . + ''; + }, + ], + ], + $users, +) ?> + +endSection() ?> diff --git a/themes/cp_admin/user/view.php b/themes/cp_admin/user/view.php new file mode 100644 index 00000000..199e3298 --- /dev/null +++ b/themes/cp_admin/user/view.php @@ -0,0 +1,16 @@ +extend('_layout') ?> + +section('pageTitle') ?> + esc($user->username), +]) ?> +endSection() ?> + + +section('content') ?> + + $user, +]) ?> + +endSection() ?> diff --git a/themes/cp_app/_admin_navbar.php b/themes/cp_app/_admin_navbar.php new file mode 100644 index 00000000..33f89e99 --- /dev/null +++ b/themes/cp_app/_admin_navbar.php @@ -0,0 +1,158 @@ +user()); ?> + +
    + + +
    + + 'html', + 'content' => esc(<<{$notificationsTitle} + HTML), + ], +]; + +if ($userPodcasts !== []) { + foreach ($userPodcasts as $userPodcast) { + $userPodcastTitle = esc($userPodcast->title); + + $unreadNotificationDotDisplayClass = in_array($userPodcast->actor_id, $actorIdsWithUnreadNotifications, true) ? '' : 'hidden'; + + $items[] = [ + 'type' => 'link', + 'title' => << +
    + + +
    + {$userPodcastTitle} +
    + HTML + , + 'uri' => route_to('notification-list', $userPodcast->id), + ]; + } +} else { + $noNotificationsText = lang('Notifications.no_notifications'); + $items[] = [ + 'type' => 'html', + 'content' => esc(<<{$noNotificationsText} + HTML), + ]; +} +?> + + + + user(), $userPodcast->id, 'interact-as')) { + $checkMark = interact_as_actor_id() === $userPodcast->actor_id ? icon('check-fill', [ + 'class' => 'ml-2 bg-accent-base text-accent-contrast rounded-full', + ]) : ''; + $userPodcastTitle = esc($userPodcast->title); + + $interactButtons .= << +
    {$userPodcastTitle}{$checkMark}
    + + HTML; + } +} + +$interactAsText = lang('Common.choose_interact'); +$interactAsRoute = route_to('interact-as-actor'); +$csrfField = csrf_field(); + +$menuItems = [ + [ + 'type' => 'link', + 'title' => lang('Navigation.account.my-account'), + 'uri' => route_to('my-account'), + ], + [ + 'type' => 'link', + 'title' => lang('Navigation.account.change-password'), + 'uri' => route_to('change-password'), + ], + [ + 'type' => 'separator', + ], + [ + 'type' => 'link', + 'title' => lang('Navigation.account.logout'), + 'uri' => route_to('logout'), + ], +]; + +if ($userPodcasts !== []) { + $menuItems = array_merge([ + [ + 'type' => 'html', + 'content' => esc(<< + {$interactAsText} +
    + {$csrfField} + {$interactButtons} +
    + + HTML), + ], + [ + 'type' => 'separator', + ], + ], $menuItems); +} +?> + +
    +
    \ No newline at end of file diff --git a/themes/cp_app/_message_block.php b/themes/cp_app/_message_block.php new file mode 100644 index 00000000..7933d6cb --- /dev/null +++ b/themes/cp_app/_message_block.php @@ -0,0 +1,19 @@ +has('message')): ?> + + + +has('error')): ?> + + + +has('errors')): ?> + +
      + +
    • + +
    +
    + diff --git a/themes/cp_app/_persons_modal.php b/themes/cp_app/_persons_modal.php new file mode 100644 index 00000000..6a41ea20 --- /dev/null +++ b/themes/cp_app/_persons_modal.php @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/themes/cp_app/embed.php b/themes/cp_app/embed.php new file mode 100644 index 00000000..4746aa1b --- /dev/null +++ b/themes/cp_app/embed.php @@ -0,0 +1,72 @@ + + + + + + + <?= esc($episode->title) ?> + + + + ' /> + asset('styles/index.css', 'css') ?> + asset('js/embed.ts', 'js') ?> + + + + <?= esc($episode->title) ?> +
    + +
    + number, $episode->season_number, 'text-xs font-semibold !no-underline border px-1 border-gray-500', true) ?> + title) ?> +
    + +

    title) ?>

    +
    + is_premium && ! is_unlocked($podcast->handle)): ?> + + + + + + loggedIn() ? $episode->audio_url : $episode->audio_url . + ($superglobals->server('HTTP_REFERER') === null + ? '?_from=' . + parse_url($superglobals->server('HTTP_REFERER'), PHP_URL_HOST) + : '') ?> + + + + + + + + + + + + + + +
    + + + diff --git a/themes/cp_app/episode/_layout-preview.php b/themes/cp_app/episode/_layout-preview.php new file mode 100644 index 00000000..9e03250e --- /dev/null +++ b/themes/cp_app/episode/_layout-preview.php @@ -0,0 +1,176 @@ + + + + + + + + + +
    + include('_admin_navbar') ?> +
    + + + +
    +
    +
    +
    +
    + parental_advisory === 'explicit', 'rounded absolute left-0 bottom-0 ml-2 mb-2 bg-black/75 text-accent-contrast') ?> + is_premium): ?> + 'absolute left-0 w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($episode->title) ?> +
    +
    + number, $episode->season_number, 'text-sm leading-none font-semibold px-1 py-1 text-white/90 border !no-underline border-subtle', true) ?> +

    title) ?>

    +
    + persons !== []): ?> + + + location): ?> + location, 'text-xs font-semibold p-2') ?> + +
    +
    +
    +
    + +
    + published_at): ?> + published_at) ?> + + + + + +
    +
    +
    +
    +

    + description_markdown, "\n") > 6 || strlen($episode->description) > 500): ?> + description_html ?> + +
    description_html ?>
    + +
    + include('episode/_partials/navigation') ?> + include('podcast/_partials/premium_banner') ?> + +
    +
    + renderSection('content') ?> +
    + + include('podcast/_partials/sidebar') ?> +
    + lang('Episode.persons_list', [ + 'episodeTitle' => esc($episode->title), + ]), + 'persons' => $episode->persons, + ]) ?> + fundingPlatforms, 'is_visible'), true)): ?> + include('podcast/_partials/funding_links_modal') ?> + + diff --git a/themes/cp_app/episode/_layout.php b/themes/cp_app/episode/_layout.php new file mode 100644 index 00000000..fcd8a7ac --- /dev/null +++ b/themes/cp_app/episode/_layout.php @@ -0,0 +1,139 @@ + + + + + + + + + +
    + include('_admin_navbar') ?> +
    + + + +
    +
    +
    +
    +
    + parental_advisory === 'explicit', 'rounded absolute left-0 bottom-0 ml-2 mb-2 bg-black/75 text-accent-contrast') ?> + is_premium): ?> + 'absolute left-0 w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($episode->title) ?> +
    +
    + number, $episode->season_number, 'text-sm leading-none font-semibold px-1 py-1 text-white/90 border !no-underline border-subtle', true) ?> +

    title) ?>

    +
    + persons !== []): ?> + + + location): ?> + location, 'text-xs font-semibold p-2') ?> + +
    +
    +
    +
    + +
    + published_at) ?> + + +
    +
    +
    +
    +

    + description_markdown, "\n") > 6 || strlen($episode->description) > 500): ?> + description_html ?> + +
    description_html ?>
    + +
    + include('episode/_partials/navigation') ?> + include('podcast/_partials/premium_banner') ?> +
    +
    + renderSection('content') ?> +
    + + include('podcast/_partials/sidebar') ?> +
    + lang('Episode.persons_list', [ + 'episodeTitle' => esc($episode->title), + ]), + 'persons' => $episode->persons, + ]) ?> + fundingPlatforms, 'is_visible'), true)): ?> + include('podcast/_partials/funding_links_modal') ?> + + diff --git a/themes/cp_app/episode/_partials/card.php b/themes/cp_app/episode/_partials/card.php new file mode 100644 index 00000000..58736f90 --- /dev/null +++ b/themes/cp_app/episode/_partials/card.php @@ -0,0 +1,41 @@ +
    +
    + + is_premium): ?> + 'absolute left-0 w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($episode->title) ?> +
    +
    +
    +
    + number, $episode->season_number, 'text-xs font-semibold border-subtle text-skin-muted px-1 border mr-2 !no-underline', true) ?> + published_at, 'text-xs whitespace-nowrap text-skin-muted') ?> +
    +

    title) ?>

    +

    description ?>

    +
    + is_premium && ! is_unlocked($podcast->handle)): ?> + + 'text-xl', + ]) ?> + + + + +
    +
    diff --git a/themes/cp_app/episode/_partials/chapter.php b/themes/cp_app/episode/_partials/chapter.php new file mode 100644 index 00000000..eb0961cb --- /dev/null +++ b/themes/cp_app/episode/_partials/chapter.php @@ -0,0 +1,13 @@ + diff --git a/themes/cp_app/episode/_partials/comment.php b/themes/cp_app/episode/_partials/comment.php new file mode 100644 index 00000000..22d3da64 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment.php @@ -0,0 +1,26 @@ + diff --git a/themes/cp_app/episode/_partials/comment_actions.php b/themes/cp_app/episode/_partials/comment_actions.php new file mode 100644 index 00000000..baafac99 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_actions.php @@ -0,0 +1,51 @@ +
    + +
    + + + +
    + replies_count): ?> + episode->podcast->handle), esc($comment->episode->slug), $comment->id), + icon('arrow-drop-down-fill', [ + 'class' => 'text-xl mr-1', + ]) . lang('Comment.view_replies', [ + 'numberOfReplies' => $comment->replies_count, + ]), + [ + 'class' => 'inline-flex items-center text-xs hover:underline', + ], + ) ?> + + + + replies_count): ?> + episode->podcast->handle), esc($comment->episode->slug), $comment->id), + icon('arrow-drop-down-fill', [ + 'class' => 'text-xl mr-1', + ]) . lang('Comment.view_replies', [ + 'numberOfReplies' => $comment->replies_count, + ]), + [ + 'class' => 'inline-flex items-center text-xs hover:underline', + ], + ) ?> + + +
    diff --git a/themes/cp_app/episode/_partials/comment_actions_from_post.php b/themes/cp_app/episode/_partials/comment_actions_from_post.php new file mode 100644 index 00000000..7ab2f4d7 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_actions_from_post.php @@ -0,0 +1,57 @@ +
    + +
    + + + +
    + replies_count): ?> + handle), $comment->id), + icon('arrow-drop-down-fill', [ + 'class' => 'text-xl mr-1', + ]) . lang('Comment.view_replies', [ + 'numberOfReplies' => $comment->replies_count, + ]), + [ + 'class' => 'inline-flex items-center text-xs hover:underline', + ], + ) ?> + + + handle), $comment->id, 'favourite'), + icon('heart-fill', [ + 'class' => 'text-xl mr-1 opacity-40', + ]) . $comment->likes_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'width' => 420, + 'height' => 620, + 'title' => lang('Post.favourites', [ + 'numberOfFavourites' => $comment->likes_count, + ]), + ], + ) ?> + replies_count): ?> + handle), $comment->id), + icon('arrow-drop-down-fill', [ + 'class' => 'text-xl mr-1', + ]) . lang('Comment.view_replies', [ + 'numberOfReplies' => $comment->replies_count, + ]), + [ + 'class' => 'inline-flex items-center text-xs hover:underline', + ], + ) ?> + + +
    diff --git a/themes/cp_app/episode/_partials/comment_card.php b/themes/cp_app/episode/_partials/comment_card.php new file mode 100644 index 00000000..e1390033 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_card.php @@ -0,0 +1,59 @@ +
    + <?= $comment->display_name ?> +
    +
    + actor->is_local + ? '' + : 'target="_blank" rel="noopener noreferrer"' ?>> + actor + ->display_name) ?> + @actor + ->username) . + ($comment->actor->is_local + ? '' + : '@' . esc($comment->actor->domain)) ?> + created_at, 'text-xs text-skin-muted ml-auto') ?> + +
    +
    message_html ?>
    + is_from_post): ?> + include('episode/_partials/comment_actions_from_post') ?> + +
    + +
    + + + +
    + + + +
    + +
    +
    diff --git a/themes/cp_app/episode/_partials/comment_reply.php b/themes/cp_app/episode/_partials/comment_reply.php new file mode 100644 index 00000000..d4ac193a --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_reply.php @@ -0,0 +1,19 @@ + diff --git a/themes/cp_app/episode/_partials/comment_reply_actions.php b/themes/cp_app/episode/_partials/comment_reply_actions.php new file mode 100644 index 00000000..631c2924 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_reply_actions.php @@ -0,0 +1,40 @@ +
    + +
    + + + + +
    + + + replies_count): ?> + episode->podcast->handle), esc($reply->episode->slug), $reply->id), + icon('chat-4-fill', [ + 'class' => 'text-2xl mr-1 opacity-40', + ]) . $reply->replies_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'title' => lang('Comment.replies', [ + 'numberOfReplies' => $reply->replies_count, + ]), + ], + ) ?> + + +
    diff --git a/themes/cp_app/episode/_partials/comment_with_replies.php b/themes/cp_app/episode/_partials/comment_with_replies.php new file mode 100644 index 00000000..6a71a0f9 --- /dev/null +++ b/themes/cp_app/episode/_partials/comment_with_replies.php @@ -0,0 +1,46 @@ +in_reply_to_id): ?> +
    +
    + $comment->reply_to_comment, + ]) ?> +
    + +include('episode/_partials/comment_card') ?> +
    + + +
    + + + <?= esc(interact_as_actor()
+        ->display_name) ?> +
    + + + +
    +
    + + +has_replies): ?> +
    + replies as $reply): ?> + $reply, + ]) ?> + +
    + + +
    diff --git a/themes/cp_app/episode/_partials/navigation.php b/themes/cp_app/episode/_partials/navigation.php new file mode 100644 index 00000000..c81b9a08 --- /dev/null +++ b/themes/cp_app/episode/_partials/navigation.php @@ -0,0 +1,58 @@ +publication_status === 'published') { + $navigationItems = [ + [ + 'uri' => route_to('episode', esc($podcast->handle), esc($episode->slug)), + 'label' => lang('Episode.comments'), + 'labelInfo' => $episode->comments_count, + ], + [ + 'uri' => route_to('episode-activity', esc($podcast->handle), esc($episode->slug)), + 'label' => lang('Episode.activity'), + 'labelInfo' => $episode->posts_count, + ], + [ + 'uri' => route_to('episode-chapters', esc($podcast->handle), esc($episode->slug)), + 'label' => lang('Episode.chapters'), + 'labelInfo' => $episode->chapters === null ? 0 : $episode->chapters->chapter_count, + ], + [ + 'uri' => route_to('episode-transcript', esc($podcast->handle), esc($episode->slug)), + 'label' => lang('Episode.transcript'), + 'labelInfo' => $episode->transcript === null ? '–' : '✓', + ], + ]; +} else { + $navigationItems = [ + [ + 'uri' => route_to('episode-preview', $episode->preview_id), + 'label' => lang('Episode.comments'), + 'labelInfo' => $episode->comments_count, + ], + [ + 'uri' => route_to('episode-preview-activity', $episode->preview_id), + 'label' => lang('Episode.activity'), + 'labelInfo' => $episode->posts_count, + ], + [ + 'uri' => route_to('episode-preview-chapters', $episode->preview_id), + 'label' => lang('Episode.chapters'), + 'labelInfo' => $episode->chapters === null ? 0 : $episode->chapters->chapter_count, + ], + [ + 'uri' => route_to('episode-preview-transcript', $episode->preview_id), + 'label' => lang('Episode.transcript'), + 'labelInfo' => $episode->transcript === null ? '–' : '✓', + ], + ]; +} + +?> + \ No newline at end of file diff --git a/themes/cp_app/episode/_partials/preview_card.php b/themes/cp_app/episode/_partials/preview_card.php new file mode 100644 index 00000000..ef26f1f0 --- /dev/null +++ b/themes/cp_app/episode/_partials/preview_card.php @@ -0,0 +1,40 @@ +
    +
    + + is_premium): ?> + 'absolute left-0 w-8 pl-2 text-2xl rounded-r-full rounded-tl-lg top-2 text-accent-contrast bg-accent-base', + ]) ?> + + <?= esc($episode->title) ?> +
    +
    +
    + number, $episode->season_number, 'text-xs font-semibold text-skin-muted px-1 border border-subtle mr-2 !no-underline', true) ?> + published_at, 'text-xs whitespace-nowrap text-skin-muted') ?> +
    + title) ?> +
    + is_premium && ! is_unlocked($episode->podcast->handle)): ?> + + 'text-xl', + ]) ?> + + + + +
    \ No newline at end of file diff --git a/themes/cp_app/episode/_partials/transcript.php b/themes/cp_app/episode/_partials/transcript.php new file mode 100644 index 00000000..af6826ab --- /dev/null +++ b/themes/cp_app/episode/_partials/transcript.php @@ -0,0 +1,9 @@ +
    + +

    + + + + +

    +
    diff --git a/themes/cp_app/episode/activity.php b/themes/cp_app/episode/activity.php new file mode 100644 index 00000000..44e2e5c1 --- /dev/null +++ b/themes/cp_app/episode/activity.php @@ -0,0 +1,37 @@ +extend('episode/_layout') ?> + +section('content') ?> + + + +
    + + + <?= esc(interact_as_actor()
+            ->display_name) ?> +
    + + + + +
    +
    +
    + + +
    + posts as $key => $post): ?> + $key, + 'post' => $post, + 'podcast' => $podcast, +]) ?> + +
    + +endSection() ?> diff --git a/themes/cp_app/episode/chapters.php b/themes/cp_app/episode/chapters.php new file mode 100644 index 00000000..0ccb0d32 --- /dev/null +++ b/themes/cp_app/episode/chapters.php @@ -0,0 +1,25 @@ +extend('episode/_layout') ?> + +section('content') ?> + + +
    + array_key_exists('title', $chapter) ? $chapter['title'] : '', + 'startTime' => format_duration($chapter['startTime']), + 'chapterImgUrl' => array_key_exists('img', $chapter) && $chapter['img'] !== '' ? $chapter['img'] : $episode->cover->thumbnail_url, + 'chapterUrl' => array_key_exists('url', $chapter) ? $chapter['url'] : '', + ]); + } ?> +
    + +
    + +endSection() ?> diff --git a/themes/cp_app/episode/comment.php b/themes/cp_app/episode/comment.php new file mode 100644 index 00000000..9031d033 --- /dev/null +++ b/themes/cp_app/episode/comment.php @@ -0,0 +1,20 @@ +extend('episode/_layout') ?> + +section('content') ?> +
    + +
    + include('episode/_partials/comment_with_replies') ?> +
    +
    + +endSection() +?> diff --git a/themes/cp_app/episode/comments.php b/themes/cp_app/episode/comments.php new file mode 100644 index 00000000..4c95cd27 --- /dev/null +++ b/themes/cp_app/episode/comments.php @@ -0,0 +1,35 @@ +extend('episode/_layout') ?> + +section('content') ?> + + + +
    + + + <?= esc(interact_as_actor()
+            ->display_name) ?> +
    + + + +
    +
    + + +
    + comments as $comment): ?> + $comment, + 'podcast' => $podcast, +]) ?> + +
    + +endSection() +?> diff --git a/themes/cp_app/episode/preview-activity.php b/themes/cp_app/episode/preview-activity.php new file mode 100644 index 00000000..31320151 --- /dev/null +++ b/themes/cp_app/episode/preview-activity.php @@ -0,0 +1,15 @@ +extend('episode/_layout-preview') ?> + +section('content') ?> + +
    + posts as $key => $post): ?> + $key, + 'post' => $post, + 'podcast' => $podcast, +]) ?> + +
    + +endSection() ?> diff --git a/themes/cp_app/episode/preview-chapters.php b/themes/cp_app/episode/preview-chapters.php new file mode 100644 index 00000000..97f4fe65 --- /dev/null +++ b/themes/cp_app/episode/preview-chapters.php @@ -0,0 +1,25 @@ +extend('episode/_layout-preview') ?> + +section('content') ?> + + +
    + array_key_exists('title', $chapter) ? $chapter['title'] : '', + 'startTime' => format_duration($chapter['startTime']), + 'chapterImgUrl' => array_key_exists('img', $chapter) ? $chapter['img'] : $episode->cover->thumbnail_url, + 'chapterUrl' => array_key_exists('url', $chapter) ? $chapter['url'] : '', + ]); + } ?> +
    + +
    + +endSection() ?> diff --git a/themes/cp_app/episode/preview-comments.php b/themes/cp_app/episode/preview-comments.php new file mode 100644 index 00000000..33925b23 --- /dev/null +++ b/themes/cp_app/episode/preview-comments.php @@ -0,0 +1,14 @@ +extend('episode/_layout-preview') ?> + +section('content') ?> + +
    + comments as $comment): ?> + $comment, + 'podcast' => $podcast, +]) ?> + +
    + +endSection() ?> \ No newline at end of file diff --git a/themes/cp_app/episode/preview-transcript.php b/themes/cp_app/episode/preview-transcript.php new file mode 100644 index 00000000..8ccfa075 --- /dev/null +++ b/themes/cp_app/episode/preview-transcript.php @@ -0,0 +1,61 @@ +extend('episode/_layout-preview') ?> + +section('content') ?> + + +
    + + '.' . $transcript->file_extension, + ]) ?> + $startTimeFormatted ?? '', + 'speaker' => $speakerLabel ?? '', + 'text' => $captionTextBlock ?? '', + ]); + $captionTextBlock = ''; + } + $startTimeFormatted = format_duration($caption['startTime']); + $speakerLabel = $caption['speaker']; + $captionTextBlock .= $captionText; + $previousSpeaker = $speakerLabel; + $renderCue = true; + } else { + // concatenate cues with the same speaker + $captionTextBlock .= ' ' . $captionText; + } + } else { + $startTimeFormatted = isset($caption['startTime']) ? format_duration($caption['startTime']) : ''; + echo view('episode/_partials/transcript', [ + 'startTime' => $startTimeFormatted, + 'speaker' => $caption['speaker'] ?? '', + 'text' => $captionText ?? '', + ]); + } + } +// render last cue if not already rendered +if ($captionTextBlock !== '') { + echo view('episode/_partials/transcript', [ + 'startTime' => $startTimeFormatted ?? '', + 'speaker' => $speakerLabel ?? '', + 'text' => $captionTextBlock ?? '', + ]); +} +?> +
    + +
    + +endSection() ?> diff --git a/themes/cp_app/episode/transcript.php b/themes/cp_app/episode/transcript.php new file mode 100644 index 00000000..b1701e75 --- /dev/null +++ b/themes/cp_app/episode/transcript.php @@ -0,0 +1,61 @@ +extend('episode/_layout') ?> + +section('content') ?> + + +
    + + '.' . $transcript->file_extension, + ]) ?> + $startTimeFormatted ?? '', + 'speaker' => $speakerLabel ?? '', + 'text' => $captionTextBlock ?? '', + ]); + $captionTextBlock = ''; + } + $startTimeFormatted = format_duration($caption['startTime']); + $speakerLabel = $caption['speaker']; + $captionTextBlock .= $captionText; + $previousSpeaker = $speakerLabel; + $renderCue = true; + } else { + // concatenate cues with the same speaker + $captionTextBlock .= ' ' . $captionText; + } + } else { + $startTimeFormatted = isset($caption['startTime']) ? format_duration($caption['startTime']) : ''; + echo view('episode/_partials/transcript', [ + 'startTime' => $startTimeFormatted, + 'speaker' => $caption['speaker'] ?? '', + 'text' => $captionText ?? '', + ]); + } + } +// render last cue if not already rendered +if ($captionTextBlock !== '') { + echo view('episode/_partials/transcript', [ + 'startTime' => $startTimeFormatted ?? '', + 'speaker' => $speakerLabel ?? '', + 'text' => $captionTextBlock ?? '', + ]); +} +?> +
    + +
    + +endSection() ?> diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php new file mode 100644 index 00000000..ee4ebea8 --- /dev/null +++ b/themes/cp_app/home.php @@ -0,0 +1,95 @@ + + + + +appendRawContent(service('vite')->asset('styles/index.css', 'css')) + ->appendRawContent(service('vite')->asset('js/app.ts', 'js')) +?> + + + + loggedIn()): ?> + include('_admin_navbar') ?> + + +
    +

    + get('App.siteName') === 'Castopod' ? 'castopod' . svg('castopod-logo-base', 'h-6 ml-2') : esc(service('settings')->get('App.siteName')) ?> +

    +
    +
    +
    + () + + +
    + +
    + + diff --git a/themes/cp_app/manifest.json b/themes/cp_app/manifest.json new file mode 100644 index 00000000..19282add --- /dev/null +++ b/themes/cp_app/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "Castopod App", + "description": "Castopod's default theme for app" +} diff --git a/themes/cp_app/pages/credits.php b/themes/cp_app/pages/credits.php new file mode 100644 index 00000000..e323b803 --- /dev/null +++ b/themes/cp_app/pages/credits.php @@ -0,0 +1,70 @@ + + + + +title(lang('Person.credits') . service('settings')->get('App.siteTitleSeparator') . service('settings')->get('App.siteName')) + ->description(lang('Page.map.description', [ + 'siteName' => esc(service('settings') + ->get('App.siteName')), + ])) +?> + + + loggedIn()): ?> + include('_admin_navbar') ?> + + +
    + +
    +
    + +
    + $groups): ?> + +

    + + +
    + <?= esc($persons['full_name']) ?> +
    + + + + + + +
    +
    +
    + + + + + + + +
    + + +
    +
    + + diff --git a/themes/cp_app/pages/map.php b/themes/cp_app/pages/map.php new file mode 100644 index 00000000..3d98cccf --- /dev/null +++ b/themes/cp_app/pages/map.php @@ -0,0 +1,43 @@ + + + + +title(lang('Page.map.title') . service('settings')->get('App.siteTitleSeparator') . service('settings')->get('App.siteName')) + ->description(lang('Page.map.description', [ + 'siteName' => esc(service('settings') + ->get('App.siteName')), + ])) +?> + + + loggedIn()): ?> + include('_admin_navbar') ?> + + +
    + +
    +
    +
    +
    + + diff --git a/themes/cp_app/pages/page.php b/themes/cp_app/pages/page.php new file mode 100644 index 00000000..580a4805 --- /dev/null +++ b/themes/cp_app/pages/page.php @@ -0,0 +1,40 @@ + + + + +title($page->title . service('settings')->get('App.siteTitleSeparator') . service('settings')->get('App.siteName')) + ->appendRawContent(service('vite')->asset('styles/index.css', 'css')) +?> + + + loggedIn()): ?> + include('_admin_navbar') ?> + + +
    + +
    +
    +
    + content_html ?> +
    +
    +
    + + 'Castopod', + ], null, false) ?> +
    + diff --git a/themes/cp_app/podcast/_layout.php b/themes/cp_app/podcast/_layout.php new file mode 100644 index 00000000..66545203 --- /dev/null +++ b/themes/cp_app/podcast/_layout.php @@ -0,0 +1,64 @@ + + + + + + + + + +
    + include('_admin_navbar') ?> +
    + + +
    +
    +
    + <?= esc($podcast->title) ?> +
    +

    title) ?>@handle) ?>

    +
    + parental_advisory === 'explicit', 'mr-1') ?> + $podcast->actor->followers_count, + ]) ?> +
    +
    +
    +
    + fundingPlatforms, 'is_visible'), true)): ?> + + + handle)), + icon('social:castopod', [ + 'class' => 'mr-2 text-xl text-black/75 group-hover:text-black', + ]) . + lang('Podcast.follow'), + [ + 'width' => 420, + 'height' => 620, + 'class' => 'group inline-flex items-center px-4 text-xs tracking-wider font-semibold text-black uppercase rounded-full leading-8 shadow bg-white', + ], + ) ?> +
    +
    + include('podcast/_partials/navigation') ?> + include('podcast/_partials/premium_banner') ?> +
    +
    + renderSection('content') ?> +
    + include('podcast/_partials/sidebar') ?> +
    + + fundingPlatforms, 'is_visible'), true)): ?> + include('podcast/_partials/funding_links_modal') ?> + + + diff --git a/themes/cp_app/podcast/_partials/funding_links_modal.php b/themes/cp_app/podcast/_partials/funding_links_modal.php new file mode 100644 index 00000000..734c492d --- /dev/null +++ b/themes/cp_app/podcast/_partials/funding_links_modal.php @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/themes/cp_app/podcast/_partials/navigation.php b/themes/cp_app/podcast/_partials/navigation.php new file mode 100644 index 00000000..0c95f099 --- /dev/null +++ b/themes/cp_app/podcast/_partials/navigation.php @@ -0,0 +1,24 @@ + route_to('podcast-activity', esc($podcast->handle)), + 'label' => lang('Podcast.activity'), + ], + [ + 'uri' => route_to('podcast-episodes', esc($podcast->handle)), + 'label' => lang('Podcast.episodes'), + ], + [ + 'uri' => route_to('podcast-about', esc($podcast->handle)), + 'label' => lang('Podcast.about'), + ], +] +?> + \ No newline at end of file diff --git a/themes/cp_app/podcast/_partials/premium_banner.php b/themes/cp_app/podcast/_partials/premium_banner.php new file mode 100644 index 00000000..8999123d --- /dev/null +++ b/themes/cp_app/podcast/_partials/premium_banner.php @@ -0,0 +1,57 @@ +is_premium): ?> + isUnlocked($podcast->handle); + // @icon("lock-unlock-fill") + // @icon("lock-fill") + $shownIcon = $isUnlocked ? 'lock-unlock-fill' : 'lock-fill'; + $hiddenIcon = $isUnlocked ? 'lock-fill' : 'lock-unlock-fill'; + ?> +
    +

    + get('Subscription.link', 'podcast:' . $podcast->id)): ?> +
    + + 'text-sm group-focus:hidden group-hover:hidden', + ]) ?> + 'hidden text-sm group-focus:block group-hover:block', + ]) ?> + + + + +
    + + + 'text-sm group-focus:hidden group-hover:hidden', + ]) ?> + 'hidden text-sm group-focus:block group-hover:block', + ]) ?> + + + +
    + \ No newline at end of file diff --git a/themes/cp_app/podcast/_partials/sidebar.php b/themes/cp_app/podcast/_partials/sidebar.php new file mode 100644 index 00000000..1292ce7f --- /dev/null +++ b/themes/cp_app/podcast/_partials/sidebar.php @@ -0,0 +1,68 @@ + + \ No newline at end of file diff --git a/themes/cp_app/podcast/about.php b/themes/cp_app/podcast/about.php new file mode 100644 index 00000000..d2426f2a --- /dev/null +++ b/themes/cp_app/podcast/about.php @@ -0,0 +1,61 @@ +extend('podcast/_layout') ?> + +section('content') ?> + +
    +
    description_html ?>
    +
    + + category) ?> + + other_categories as $other_category): ?> + + + + +
    + +
    + persons !== []): ?> + + + location): ?> + location, 'text-xs font-semibold p-2') ?> + +
    +
    +

    +
    + $value): ?> + + + + +
    +
    +
    + + + lang('Podcast.persons_list', [ + 'podcastTitle' => esc($podcast->title), + ]), + 'persons' => $podcast->persons, +]) ?> + +endSection() +?> diff --git a/themes/cp_app/podcast/activity.php b/themes/cp_app/podcast/activity.php new file mode 100644 index 00000000..8d6c21f8 --- /dev/null +++ b/themes/cp_app/podcast/activity.php @@ -0,0 +1,49 @@ +extend('podcast/_layout') ?> + +section('content') ?> + + +
    + + + <?= esc(interact_as_actor()
+        ->display_name) ?> +
    + + + + + +
    +
    +
    + + + +
    + $post): ?> + reblog_of_id !== null): ?> + $key, + 'post' => $post->reblog_of_post, + 'podcast' => $podcast, +]) ?> + + $key, + 'post' => $post, + 'podcast' => $podcast, +]) ?> + + +
    + +endSection() ?> diff --git a/themes/cp_app/podcast/episodes.php b/themes/cp_app/podcast/episodes.php new file mode 100644 index 00000000..6adcf32a --- /dev/null +++ b/themes/cp_app/podcast/episodes.php @@ -0,0 +1,57 @@ +extend('podcast/_layout') ?> + +section('content') ?> + + +
    +

    + + $activeQuery['value'], + 'episodeCount' => count($episodes), +]) ?> + + $activeQuery['value'], + 'episodeCount' => count($episodes), +]) ?> + +

    + + + + +
    +
    + + $episode, + 'podcast' => $podcast, + ]) ?> + +
    + +

    + + +endSection() +?> diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php new file mode 100644 index 00000000..8253fd23 --- /dev/null +++ b/themes/cp_app/podcast/follow.php @@ -0,0 +1,55 @@ + + + + + +appendRawContent(service('vite')->asset('styles/index.css', 'css')) + ->appendRawContent(service('vite')->asset('js/podcast.ts', 'js')) +?> + + +
    +

    +
    + +
    + <?= esc($actor->display_name) ?> +
    +

    display_name) ?>

    +

    +@username) ?>@domain) ?>

    +
    +
    +
    +
    + +
    +
    + + + + + + +
    + + + diff --git a/themes/cp_app/podcast/links.php b/themes/cp_app/podcast/links.php new file mode 100644 index 00000000..14ea641e --- /dev/null +++ b/themes/cp_app/podcast/links.php @@ -0,0 +1,93 @@ + + + + + +appendRawContent(service('vite')->asset('styles/index.css', 'css')) + ->appendRawContent(service('vite')->asset('js/app.ts', 'js')) + ->appendRawContent(service('vite')->asset('js/podcast.ts', 'js')) +?> + + + +
    + include('_admin_navbar') ?> +
    + + +
    +
    +
    + <?= esc($podcast->title) ?> + +

    title) ?>@handle) ?>

    +
    +
    + fundingPlatforms, 'is_visible'), true)): ?> + + + handle)), + icon('social:castopod', [ + 'class' => 'mr-2 text-xl text-black/75 group-hover:text-black', + ]) . lang('Podcast.follow'), + [ + 'width' => 420, + 'height' => 620, + 'class' => 'group inline-flex items-center px-4 text-xs tracking-wider font-semibold text-black uppercase rounded-full leading-8 shadow bg-white', + ], + ) ?> + +
    +
    +
    +
    + 'text-xl mr-auto', + ]) ?> + + podcastingPlatforms as $podcastingPlatform): ?> + is_visible && $podcastingPlatform->slug !== 'castopod'): ?> + type . ':' . $podcastingPlatform->slug, [ + 'class' => 'text-xl mr-auto', + ]) ?>label ?> + + + +
    +
    + socialPlatforms as $socialPlatform): ?> + is_visible): ?> + link_url), + icon($socialPlatform->type . ':' . $socialPlatform->slug), + [ + 'class' => 'focus:ring-accent rounded-full text-4xl text-skin-muted hover:text-skin-base w-8 h-8 items-center inline-flex justify-center', + 'target' => '_blank', + 'rel' => 'noopener noreferrer', + 'data-tooltip' => 'bottom', + 'title' => $socialPlatform->label, + ], + ) ?> + + +
    + + fundingPlatforms, 'is_visible'), true)): ?> + include('podcast/_partials/funding_links_modal') ?> + + + diff --git a/themes/cp_app/podcast/unlock.php b/themes/cp_app/podcast/unlock.php new file mode 100644 index 00000000..5033c098 --- /dev/null +++ b/themes/cp_app/podcast/unlock.php @@ -0,0 +1,83 @@ + + + + + + + + + +
    + include('_admin_navbar') ?> +
    + + +
    + +
    + + 'p-4 text-6xl rounded-full bg-base text-accent-base', + ]) ?> + +

    esc($podcast->title), + ]) ?>

    + + + + + get('Subscription.link', 'podcast:' . $podcast->id)): ?> +

    + esc($podcast->title), + ]) ?> + +

    + + +
    + +
    +
    +
    + <?= esc($podcast->title) ?> +
    +
    title) ?>@handle) ?>
    +
    + parental_advisory === 'explicit', 'mr-1') ?> + $podcast->actor->followers_count, + ]) ?> +
    +
    +
    +
    + fundingPlatforms, 'is_visible'), true)): ?> + + +
    +
    + include('podcast/_partials/navigation') ?> +
    +
    + include('podcast/_partials/sidebar') ?> +
    + + fundingPlatforms, 'is_visible'), true)): ?> + include('podcast/_partials/funding_links_modal') ?> + + + diff --git a/themes/cp_app/post/_partials/actions.php b/themes/cp_app/post/_partials/actions.php new file mode 100644 index 00000000..456cbae8 --- /dev/null +++ b/themes/cp_app/post/_partials/actions.php @@ -0,0 +1,137 @@ +
    + +
    + + handle), $post->id), + icon('chat-4-fill', [ + 'class' => 'text-2xl mr-1 opacity-40', + ]) . $post->replies_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'title' => lang('Post.replies', [ + 'numberOfReplies' => $post->replies_count, + ]), + ], + ) ?> + is_private): ?> + + + + + + +
    + + + handle), $post->id), + icon('chat-4-fill', [ + 'class' => 'text-2xl mr-1 opacity-40', + ]) . $post->replies_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'title' => lang('Post.replies', [ + 'numberOfReplies' => $post->replies_count, + ]), + ], + ) ?> + handle), $post->id, 'reblog'), + icon('repeat-fill', [ + 'class' => 'text-2xl mr-1 opacity-40', + ]) . $post->reblogs_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'width' => 420, + 'height' => 620, + 'title' => lang('Post.reblogs', [ + 'numberOfReblogs' => $post->reblogs_count, + ]), + ], + ) ?> + handle), $post->id, 'favourite'), + icon('heart-fill', [ + 'class' => 'text-2xl mr-1 opacity-40', + ]) . $post->favourites_count, + [ + 'class' => 'inline-flex items-center hover:underline', + 'width' => 420, + 'height' => 620, + 'title' => lang('Post.favourites', [ + 'numberOfFavourites' => $post->favourites_count, + ]), + ], + ) ?> + +
    diff --git a/themes/cp_app/post/_partials/card.php b/themes/cp_app/post/_partials/card.php new file mode 100644 index 00000000..108a87cd --- /dev/null +++ b/themes/cp_app/post/_partials/card.php @@ -0,0 +1,41 @@ +
    +
    + <?= esc($post->actor->display_name) ?> + +
    + message, "\n") >= 3 || strlen($post->message) > 250): ?> + message_html ?> + +
    message_html ?>
    + + episode_id && $post->in_reply_to_id === null): ?> + $index, + 'episode' => $post->episode, +]) ?> + preview_card): ?> + $post->preview_card, + ]) ?> + + include('post/_partials/actions') ?> +
    diff --git a/themes/cp_app/post/_partials/post_with_replies.php b/themes/cp_app/post/_partials/post_with_replies.php new file mode 100644 index 00000000..6586b8c2 --- /dev/null +++ b/themes/cp_app/post/_partials/post_with_replies.php @@ -0,0 +1,64 @@ +in_reply_to_id): ?> +
    +
    + $podcast, + 'reply' => $post->reply_to_post, + ]) ?> +
    + + $index, + 'post' => $post, + 'podcast' => $podcast, +]) ?> +
    +
    + +
    + + + <?= esc(interact_as_actor()
+                    ->display_name) ?> +
    + + + +
    +
    + + handle), $post->id, 'reply'), + lang('Post.reply_to', [ + 'actorUsername' => esc($post->actor->username), + ]), + [ + 'class' => 'text-center justify-center font-semibold rounded-full shadow relative z-10 px-4 py-2 w-full bg-accent-base text-accent-contrast inline-flex items-center hover:bg-accent-hover', + 'width' => 420, + 'height' => 620, + ], + ) ?> + +
    + + has_replies): ?> +
    + replies as $reply): ?> + $podcast, + 'reply' => $reply, + ]) ?> + +
    + +
    \ No newline at end of file diff --git a/themes/cp_app/post/_partials/preview_card.php b/themes/cp_app/post/_partials/preview_card.php new file mode 100644 index 00000000..0389e636 --- /dev/null +++ b/themes/cp_app/post/_partials/preview_card.php @@ -0,0 +1,50 @@ +type === 'image'): ?> + + image): ?> +
    + 'absolute inset-0 m-auto text-6xl bg-accent-base bg-opacity-50 group-hover:bg-opacity-100 text-accent-contrast rounded-full p-2', + ], + ) ?> + <?= esc($preview_card->title) ?> +
    + + +
    + provider_name) ?> +
    +
    +type === 'video'): ?> + + image): ?> +
    + 'absolute inset-0 m-auto text-6xl bg-accent-base bg-opacity-50 group-hover:bg-opacity-100 text-accent-contrast rounded-full p-2', + ], + ) ?> + <?= esc($preview_card->title) ?> +
    + + +
    + provider_name) ?> + title) ?> +
    +
    + + + image): ?> + <?= esc($preview_card->title) ?> + +

    + provider_name) ?> + title) ?> +

    +
    + diff --git a/themes/cp_app/post/_partials/reblog.php b/themes/cp_app/post/_partials/reblog.php new file mode 100644 index 00000000..95eaf4da --- /dev/null +++ b/themes/cp_app/post/_partials/reblog.php @@ -0,0 +1,34 @@ +
    +

    'text-lg mr-2 opacity-40', + ], + ) . lang('Post.actor_shared', [ + 'actor' => esc($post->actor->display_name), + ]) ?>

    +
    + <?= esc($post->actor->display_name) ?> + +
    +
    message_html ?>
    + episode_id) : ?> + $index, + 'episode' => $post->episode, + ]) ?> + preview_card_id) : ?> + $post->preview_card, + ]) ?> + + include('post/_partials/actions') ?> +
    diff --git a/themes/cp_app/post/_partials/reply.php b/themes/cp_app/post/_partials/reply.php new file mode 100644 index 00000000..6c3db6d5 --- /dev/null +++ b/themes/cp_app/post/_partials/reply.php @@ -0,0 +1,26 @@ + diff --git a/themes/cp_app/post/_partials/reply_actions.php b/themes/cp_app/post/_partials/reply_actions.php new file mode 100644 index 00000000..0fe3560a --- /dev/null +++ b/themes/cp_app/post/_partials/reply_actions.php @@ -0,0 +1,138 @@ + +
    +
    + + handle), $reply->id), + icon('chat-4-fill', [ + 'class' => 'text-lg mr-1 opacity-40', + ]) . $reply->replies_count, + [ + 'class' => 'inline-flex items-center hover:underline text-sm', + 'title' => lang('Post.replies', [ + 'numberOfReplies' => $reply->replies_count, + ]), + ], + ) ?> + is_private): ?> + + + + + + +
    + +
    + +
    + handle), $reply->id), + icon('chat-4-fill', [ + 'class' => 'text-lg mr-1 opacity-40', + ]) . $reply->replies_count, + [ + 'class' => 'inline-flex items-center hover:underline text-sm', + 'title' => lang('Post.replies', [ + 'numberOfReplies' => $reply->replies_count, + ]), + ], + ) ?> + handle), $reply->id, 'reblog'), + icon('repeat-fill', [ + 'class' => 'text-lg mr-1 opacity-40', + ]) . $reply->reblogs_count, + [ + 'class' => 'inline-flex items-center hover:underline text-sm', + 'width' => 420, + 'height' => 620, + 'title' => lang('Post.reblogs', [ + 'numberOfReblogs' => $reply->reblogs_count, + ]), + ], + ) ?> + handle), $reply->id, 'favourite'), + icon('heart-fill', [ + 'class' => 'text-lg mr-1 opacity-40', + ]) . $reply->favourites_count, + [ + 'class' => 'inline-flex items-center hover:underline text-sm', + 'width' => 420, + 'height' => 620, + 'title' => lang('Post.favourites', [ + 'numberOfFavourites' => $reply->favourites_count, + ]), + ], + ) ?> +
    + diff --git a/themes/cp_app/post/post.php b/themes/cp_app/post/post.php new file mode 100644 index 00000000..a9cd34b2 --- /dev/null +++ b/themes/cp_app/post/post.php @@ -0,0 +1,23 @@ +extend('podcast/_layout') ?> + +section('content') ?> + +
    + 1, + 'post' => $post, + 'podcast' => $podcast, + ]) ?> +
    +endSection() ?> diff --git a/themes/cp_app/post/remote_action.php b/themes/cp_app/post/remote_action.php new file mode 100644 index 00000000..be338675 --- /dev/null +++ b/themes/cp_app/post/remote_action.php @@ -0,0 +1,45 @@ + + + +appendRawContent(service('vite')->asset('styles/index.css', 'css')) + ->appendRawContent(service('vite')->asset('js/podcast.ts', 'js')) +?> + + +
    +

    +
    +
    + 1, + 'podcast' => $podcast, + 'post' => $post, + ]) ?> + +
    + + + + + + + +
    + + diff --git a/themes/cp_auth/_layout.php b/themes/cp_auth/_layout.php new file mode 100644 index 00000000..7ea7d7b2 --- /dev/null +++ b/themes/cp_auth/_layout.php @@ -0,0 +1,34 @@ + + + + +title('Castopod Auth') + ->description('Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.'); +?> + + +
    + + + +
    +
    + renderSection( + 'pageTitle', + ) ?> + + renderSection('content') ?> +
    + + diff --git a/themes/cp_auth/_message_block.php b/themes/cp_auth/_message_block.php new file mode 100644 index 00000000..7933d6cb --- /dev/null +++ b/themes/cp_auth/_message_block.php @@ -0,0 +1,19 @@ +has('message')): ?> + + + +has('error')): ?> + + + +has('errors')): ?> + +
      + +
    • + +
    +
    + diff --git a/themes/cp_auth/email_2fa_show.php b/themes/cp_auth/email_2fa_show.php new file mode 100644 index 00000000..3678039d --- /dev/null +++ b/themes/cp_auth/email_2fa_show.php @@ -0,0 +1,26 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> endSection() ?> + +section('content') ?> + +
    + + + + + + + + +endSection() ?> diff --git a/themes/cp_auth/email_2fa_verify.php b/themes/cp_auth/email_2fa_verify.php new file mode 100644 index 00000000..9d761fd1 --- /dev/null +++ b/themes/cp_auth/email_2fa_verify.php @@ -0,0 +1,26 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> endSection() ?> + +section('content') ?> + +
    + + + + + + + +endSection() ?> diff --git a/themes/cp_auth/email_activate_show.php b/themes/cp_auth/email_activate_show.php new file mode 100644 index 00000000..85f45849 --- /dev/null +++ b/themes/cp_auth/email_activate_show.php @@ -0,0 +1,28 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?>endSection() ?> + +section('content') ?> + +

    + +
    + + + + + + + + +endSection() ?> diff --git a/themes/cp_auth/emails/email_2fa_email.php b/themes/cp_auth/emails/email_2fa_email.php new file mode 100644 index 00000000..bbc010c5 --- /dev/null +++ b/themes/cp_auth/emails/email_2fa_email.php @@ -0,0 +1 @@ +

    diff --git a/themes/cp_auth/emails/email_activate_email.php b/themes/cp_auth/emails/email_activate_email.php new file mode 100644 index 00000000..9686df46 --- /dev/null +++ b/themes/cp_auth/emails/email_activate_email.php @@ -0,0 +1,3 @@ +

    + +

    diff --git a/themes/cp_auth/emails/magic_link_email.php b/themes/cp_auth/emails/magic_link_email.php new file mode 100644 index 00000000..a7731f59 --- /dev/null +++ b/themes/cp_auth/emails/magic_link_email.php @@ -0,0 +1,6 @@ +

    +
    + + ?token= + +

    diff --git a/themes/cp_auth/emails/welcome_email.php b/themes/cp_auth/emails/welcome_email.php new file mode 100644 index 00000000..6d89308c --- /dev/null +++ b/themes/cp_auth/emails/welcome_email.php @@ -0,0 +1,11 @@ +

    + current_domain(), + 'numberOfHours' => setting('Auth.welcomeLinkLifetime') / 3600, +]) ?>

    + +
    + + ?token= + +

    diff --git a/themes/cp_auth/login.php b/themes/cp_auth/login.php new file mode 100644 index 00000000..df2992eb --- /dev/null +++ b/themes/cp_auth/login.php @@ -0,0 +1,52 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?>endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + + +endSection() ?> + + +section('footer') ?> + +
    + +

    + + +

    + +
    + +endSection() ?> diff --git a/themes/cp_auth/magic_link_form.php b/themes/cp_auth/magic_link_form.php new file mode 100644 index 00000000..0170de00 --- /dev/null +++ b/themes/cp_auth/magic_link_form.php @@ -0,0 +1,24 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> endSection() ?> + +section('content') ?> + +
    + + + + + + + +endSection() ?> diff --git a/themes/cp_auth/magic_link_message.php b/themes/cp_auth/magic_link_message.php new file mode 100644 index 00000000..eed77d74 --- /dev/null +++ b/themes/cp_auth/magic_link_message.php @@ -0,0 +1,13 @@ +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> endSection() ?> + +section('content') ?> + +

    + +

    + + + +endSection() ?> diff --git a/themes/cp_auth/magic_link_set_password.php b/themes/cp_auth/magic_link_set_password.php new file mode 100644 index 00000000..9b29aec4 --- /dev/null +++ b/themes/cp_auth/magic_link_set_password.php @@ -0,0 +1,26 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + +endSection() ?> diff --git a/themes/cp_auth/manifest.json b/themes/cp_auth/manifest.json new file mode 100644 index 00000000..917784f9 --- /dev/null +++ b/themes/cp_auth/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "Castopod Auth", + "description": "Castopod's default theme for authentication" +} diff --git a/themes/cp_auth/register.php b/themes/cp_auth/register.php new file mode 100644 index 00000000..09dd9d1e --- /dev/null +++ b/themes/cp_auth/register.php @@ -0,0 +1,62 @@ + +extend(config('Auth')->views['layout']) ?> + +section('pageTitle') ?> + +endSection() ?> + + +section('content') ?> + +
    + + + + + + + + + + + + + + +endSection() ?> + + +section('footer') ?> + +

    + +

    + +endSection() ?> diff --git a/themes/cp_install/_layout.php b/themes/cp_install/_layout.php new file mode 100644 index 00000000..dd58580d --- /dev/null +++ b/themes/cp_install/_layout.php @@ -0,0 +1,24 @@ + + + +title(lang('Install.title')) ?> + + +
    +
    + +
    +
    +
    + + renderSection('content') ?> +
    + + diff --git a/themes/cp_install/_message_block.php b/themes/cp_install/_message_block.php new file mode 100644 index 00000000..7933d6cb --- /dev/null +++ b/themes/cp_install/_message_block.php @@ -0,0 +1,19 @@ +has('message')): ?> + + + +has('error')): ?> + + + +has('errors')): ?> + +
      + +
    • + +
    +
    + diff --git a/themes/cp_install/cache_config.php b/themes/cp_install/cache_config.php new file mode 100644 index 00000000..f8f4e02d --- /dev/null +++ b/themes/cp_install/cache_config.php @@ -0,0 +1,35 @@ +extend('_layout') ?> + +section('content') ?> + +
    + + +
    +
    + 3/4 + +
    + +

    +
    + + + + + + + +endSection() ?> diff --git a/themes/cp_install/create_superadmin.php b/themes/cp_install/create_superadmin.php new file mode 100644 index 00000000..b27926ed --- /dev/null +++ b/themes/cp_install/create_superadmin.php @@ -0,0 +1,36 @@ +extend('_layout') ?> + +section('content') ?> + + + + +
    + 4/4 + +
    + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_install/database_config.php b/themes/cp_install/database_config.php new file mode 100644 index 00000000..d4d30915 --- /dev/null +++ b/themes/cp_install/database_config.php @@ -0,0 +1,59 @@ +extend('_layout') ?> + +section('content') ?> + +
    + + +
    +
    + 2/4 + +
    + +

    +
    + + + + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_install/instance_config.php b/themes/cp_install/instance_config.php new file mode 100644 index 00000000..43a48a9b --- /dev/null +++ b/themes/cp_install/instance_config.php @@ -0,0 +1,41 @@ +extend('_layout') ?> + +section('content') ?> + +
    + + +
    + 1/4 + +
    + + + + + + + + + + + + +endSection() ?> diff --git a/themes/cp_install/manifest.json b/themes/cp_install/manifest.json new file mode 100644 index 00000000..fb454c17 --- /dev/null +++ b/themes/cp_install/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "Castopod Install", + "description": "Castopod's default theme for install wizard" +} diff --git a/themes/cp_install/manual_config.php b/themes/cp_install/manual_config.php new file mode 100644 index 00000000..7ce6e415 --- /dev/null +++ b/themes/cp_install/manual_config.php @@ -0,0 +1,18 @@ +extend('_layout') ?> + +section('content') ?> + +

    +
    + 'mr-2 flex-shrink-0', +]) . lang('Install.messages.writeError') ?> +
    +

    + +endSection() +?> diff --git a/tsconfig.json b/tsconfig.json index 5f495c6b..1929331b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,15 +2,8 @@ "compilerOptions": { /* Basic Options */ "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "lib": [ - "DOM", - "DOM.Iterable", - "ESNext" - ] /* Specify library files to be included in the compilation. */, - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "app/Resources/types", - "rootDir": "app/Resources", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "noEmit": true, /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, @@ -26,8 +19,8 @@ /* Module Resolution Options */ "moduleResolution": "node", - "baseUrl": "app/Resources/js" /* Base directory to resolve non-absolute module names. */ + "baseUrl": "resources/js" /* Base directory to resolve non-absolute module names. */ }, - "include": ["app/Resources/js/**/*.ts"], + "include": ["resources/js/**/*.ts"], "exclude": [] } diff --git a/vite-manifest-css.ts b/vite-manifest-css.ts deleted file mode 100644 index 68f2f927..00000000 --- a/vite-manifest-css.ts +++ /dev/null @@ -1,67 +0,0 @@ -// This plugin adds a `manifest-css.json` file for css assets to help reference them from the backend -// Adapted from https://github.com/ElMassimo/vite_ruby/blob/main/vite-plugin-ruby/src/manifest.ts - -import path from "path"; -import { OutputBundle } from "rollup"; -import type { Plugin, ResolvedConfig } from "vite"; - -interface AssetsManifestChunk { - src?: string; - file: string; -} - -type AssetsManifest = Map; - -// Internal: Returns the filename without the last extension. -function withoutExtension(filename: string) { - return filename.substr(0, filename.lastIndexOf(".")); -} - -// Internal: Writes a manifest file that allows to map an entrypoint asset file -// name to the corresponding output file name. -export function ManifestCSS(): Plugin { - let config: ResolvedConfig; - - // Internal: For stylesheets Vite does not output the result to the manifest, - // so we extract the file name of the processed asset from the Rollup bundle. - function extractChunkStylesheets( - bundle: OutputBundle, - manifest: AssetsManifest - ) { - const cssFiles = new Set( - Object.values(config.build.rollupOptions.input as Record) - .filter((file) => new RegExp(`\\.css$`).test(file)) - .map((file) => path.relative(config.root, file)) - ); - - Object.values(bundle) - .filter((chunk) => chunk.type === "asset" && chunk.name) - .forEach((chunk) => { - // NOTE: Rollup appends `.css` to the file so it's removed before matching. - // See `resolveEntrypointsForRollup`. - const src = withoutExtension(chunk.name!); - if (cssFiles.has(src)) { - manifest.set(src, { file: chunk.fileName, src }); - } - }); - } - - return { - name: "vite-assets-manifest", - apply: "build", - enforce: "post", - configResolved(resolvedConfig: ResolvedConfig) { - config = resolvedConfig; - }, - async generateBundle(_options, bundle) { - const manifest: AssetsManifest = new Map(); - extractChunkStylesheets(bundle, manifest); - - this.emitFile({ - fileName: "manifest-css.json", - type: "asset", - source: JSON.stringify(Object.fromEntries(manifest), null, 2), - }); - }, - }; -} diff --git a/vite.config.ts b/vite.config.ts index b2d623b9..de7f650b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,25 +1,43 @@ -import { defineConfig } from "vite"; -import { ManifestCSS } from "./vite-manifest-css"; +import path from "path"; +import { defineConfig, loadEnv } from "vite"; +import { VitePWA } from "vite-plugin-pwa"; +import codeigniter from "vite-plugin-codeigniter"; -// https://vitejs.dev/config/ -export default defineConfig({ - root: "./app/Resources", - base: "/assets/", - build: { - outDir: "../../public/assets", - assetsDir: "", - manifest: true, - sourcemap: true, - rollupOptions: { - input: { - "podcast.ts": "app/Resources/js/podcast.ts", - "install.ts": "app/Resources/js/install.ts", - "admin.ts": "app/Resources/js/admin.ts", - "charts.ts": "app/Resources/js/charts.ts", - "map.ts": "app/Resources/js/map.ts", - "styles/index.css": "app/Resources/styles/index.css", - }, +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd()); + + return { + server: { + host: true, + port: env.VITE_PORT || 5173, + strictPort: true, }, - }, - plugins: [ManifestCSS()], + plugins: [ + codeigniter({ + imageVariants: [ + { + src: "images/castopod-banner-*.jpg", + sizes: { + "%NAME%_small.webp": 320, + "%NAME%_medium.webp": 960, + "%NAME%_federation.jpg": 1500, + }, + }, + { + src: "images/castopod-avatar.jpg", + sizes: { + "%NAME%_tiny.webp": 40, + "%NAME%_thumbnail.webp": 150, + "%NAME%_medium.webp": 320, + "%NAME%_federation.jpg": 400, + }, + }, + ], + }), + VitePWA({ + manifest: false, + outDir: path.resolve(__dirname, "public/assets"), + }), + ], + }; }); diff --git a/writable/.htaccess b/writable/.htaccess index f24db0ac..97c65d2d 100644 --- a/writable/.htaccess +++ b/writable/.htaccess @@ -1,6 +1,6 @@ - Require all denied + Require all denied - Deny from all - + Deny from all + \ No newline at end of file diff --git a/writable/cache/index.html b/writable/cache/index.html index eebf8ecb..cf672743 100644 --- a/writable/cache/index.html +++ b/writable/cache/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/writable/debugbar/index.html b/writable/debugbar/index.html new file mode 100644 index 00000000..cf672743 --- /dev/null +++ b/writable/debugbar/index.html @@ -0,0 +1,9 @@ + + + + 403 Forbidden + + +

    Directory access is forbidden.

    + + diff --git a/writable/index.html b/writable/index.html new file mode 100644 index 00000000..cf672743 --- /dev/null +++ b/writable/index.html @@ -0,0 +1,9 @@ + + + + 403 Forbidden + + +

    Directory access is forbidden.

    + + diff --git a/writable/logs/index.html b/writable/logs/index.html index eebf8ecb..cf672743 100644 --- a/writable/logs/index.html +++ b/writable/logs/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/writable/session/index.html b/writable/session/index.html index eebf8ecb..cf672743 100644 --- a/writable/session/index.html +++ b/writable/session/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden diff --git a/writable/temp/index.html b/writable/temp/index.html new file mode 100644 index 00000000..cf672743 --- /dev/null +++ b/writable/temp/index.html @@ -0,0 +1,9 @@ + + + + 403 Forbidden + + +

    Directory access is forbidden.

    + + diff --git a/writable/uploads/index.html b/writable/uploads/index.html index eebf8ecb..cf672743 100644 --- a/writable/uploads/index.html +++ b/writable/uploads/index.html @@ -1,4 +1,4 @@ - + 403 Forbidden