diff --git a/.docker/entrypoint.sh b/.docker/entrypoint.sh index bd552f22..e3aec65a 100755 --- a/.docker/entrypoint.sh +++ b/.docker/entrypoint.sh @@ -83,6 +83,61 @@ function prepareKimai() { echo "Kimai is ready" } +function ensureAppSecret() { + # GHSA-jr9p-4h4j-6c58 + # Make sure the container never runs with the publicly-known default APP_SECRET. + # If the user provided their own value (via -e APP_SECRET=...) it is kept untouched. + # Otherwise a unique secret is generated once and persisted below var/data, which + # is the directory mounted as a named volume in the documented Docker setup, so it + # stays stable across container restarts and re-creations. + # + # Disable xtrace around all reads/writes of APP_SECRET so the secret never appears + # in container logs. The braces around `set +x` keep the disable command itself + # from being traced. + { set +x; } 2>/dev/null + + local SECRET_FILE=/opt/kimai/var/data/.appsecret + local ENV_LOCAL=/opt/kimai/.env.local + + # Always remove any prior .env.local before deciding which secret applies. + # This prevents a stale auto-generated value from lingering after a user + # later sets APP_SECRET via docker env / compose. It is regenerated below + # in the auto-secret path; in the user-provided path it stays absent so + # the real env var remains the single source of truth. + rm -f "$ENV_LOCAL" + + if [ -n "$APP_SECRET" ] && [ "$APP_SECRET" != "change_this_to_something_unique" ]; then + set -x + return + fi + + if [ -s "$SECRET_FILE" ]; then + APP_SECRET=$(cat "$SECRET_FILE") + echo "APP_SECRET: using persisted auto-generated secret" + else + mkdir -p "$(dirname "$SECRET_FILE")" + APP_SECRET=$(php -r 'echo bin2hex(random_bytes(32));') + ( umask 077 && echo "$APP_SECRET" > "$SECRET_FILE" ) + chown "$USER_ID:$GROUP_ID" "$SECRET_FILE" + echo "APP_SECRET: generated a new unique secret, persisted to var/data volume" + fi + export APP_SECRET + + # Mirror the resolved secret into .env.local so Symfony's Dotenv picks up + # the right value when commands are run via `docker exec` (which does not + # inherit the entrypoint's exported env). .env.local is Symfony's official + # override file and is loaded before .env. Rewritten on every container + # start; the source of truth is the persisted SECRET_FILE above. + ( umask 077 && echo "APP_SECRET=$APP_SECRET" > "$ENV_LOCAL" ) + # The PHP runtime (apache/php-fpm) runs as $USER_ID:$GROUP_ID and must be + # able to read .env.local; the entrypoint itself runs as root, so the file + # would otherwise be 0600 root:root and unreadable to the web user, causing + # Symfony's Dotenv to throw PathException at boot. + chown "$USER_ID:$GROUP_ID" "$ENV_LOCAL" + + set -x +} + function runServer() { # Just while I'm fixing things /opt/kimai/bin/console kimai:reload --env="$APP_ENV" @@ -98,5 +153,6 @@ function runServer() { waitForDB handleStartup +ensureAppSecret prepareKimai runServer diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..56d58bef --- /dev/null +++ b/.dockerignore @@ -0,0 +1,76 @@ +# Secrets and local environment +.env +.env.* +!.env.dist +.dockerhub.secrets +config/secrets/* + +# Git and CI +.git +.gitattributes +.gitignore +.github + +# Build artifacts and dependencies (installed inside the image) +vendor/ +node_modules/ +public/bundles/ +.pnpm-store/ +.yarn/ +.yarnrc.yml +.pnp.* + +# Symfony runtime data — exclude contents but keep the directories themselves +# (the dirs are tracked in git via .gitkeep and code expects them to exist) +var/advisories/ +var/cache/* +var/log/* +var/sessions/* +var/data/* +var/dev/* +var/invoices/* +var/export/* +var/packages/* +var/plugins/* +var/templates/* +!var/**/.gitkeep + +# IDE, tools, caches +.idea/ +.claude/ +.vscode/ +.php-cs-fixer.cache +.php_cs.cache +.phpunit.result.cache +.phpunit/ +nbproject/ + +# Dev-only configs +test/ +.php-cs-fixer.dist.php +php-cs-fixer.sh +phpstan.sh +phpstan.neon +phpstan-baseline.neon +eslint.config.mjs +.editorconfig +.codecov.yml +phpunit.xml +phpunit.xml.dist + +# Docker and compose (not needed inside the image; .docker/ is copied explicitly) +docker-compose.yml +docker-compose.*.yml +Dockerfile +.dockerignore + +# OS junk +.DS_Store +Thumbs.db + +# Local Symfony overrides +public/.user.ini +php.ini +.php-version +config/packages/local.yaml +config/bundles-local.php diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c34cc467..f6d6164c 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -9,32 +9,28 @@ on: release: types: [released] +concurrency: + group: docker-build + cancel-in-progress: true + +permissions: {} + jobs: build: + name: Docker images runs-on: ubuntu-latest - steps: - - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to DockerHub - uses: docker/login-action@v4 - with: - username: ${{secrets.DOCKERHUB_USERNAME}} - password: ${{secrets.DOCKERHUB_PASSWORD}} - - name: Determine version + env: + GITHUB_EVENT_INPUTS_KIMAI_TAG: ${{ github.event.inputs.kimai_tag }} + GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} run: | - input="${{ github.event.inputs.kimai_tag }}" - + input="${GITHUB_EVENT_INPUTS_KIMAI_TAG}" + # Determine between manual trigger and release event if [ -z "$input" ]; then - echo "Using release tag: ${{ github.event.release.tag_name }}" - version="${{ github.event.release.tag_name }}" + echo "Using release tag: ${GITHUB_EVENT_RELEASE_TAG_NAME}" + version="${GITHUB_EVENT_RELEASE_TAG_NAME}" else echo "Using tag provided: $input" version="$input" @@ -44,11 +40,45 @@ jobs: echo "Invalid version number: $version" exit 1 fi - + echo "kimai_version=$version" >> $GITHUB_ENV + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ env.kimai_version }} + persist-credentials: false + + - name: Install buildx + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + + - name: Login to DockerHub + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + with: + username: ${{secrets.DOCKERHUB_USERNAME}} + password: ${{secrets.DOCKERHUB_PASSWORD}} + + # TODO 3.0 remove kimai/kimai2:apache and kimai/kimai2:apache- + - name: Apache image + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 + with: + context: . + file: Dockerfile + build-args: | + KIMAI=${{ env.kimai_version }} + BASE=apache + target: prod + platforms: linux/amd64,linux/arm64 + tags: | + kimai/kimai2:stable + kimai/kimai2:apache + kimai/kimai2:2 + kimai/kimai2:${{ env.kimai_version }} + push: true + + # TODO 3.0 remove the deprecated FPM build - name: FPM image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: Dockerfile @@ -62,24 +92,8 @@ jobs: kimai/kimai2:fpm push: true - - name: Apache image - uses: docker/build-push-action@v6 - with: - context: . - file: Dockerfile - build-args: | - KIMAI=${{ env.kimai_version }} - BASE=apache - target: prod - platforms: linux/amd64,linux/arm64 - tags: | - kimai/kimai2:stable - kimai/kimai2:apache - kimai/kimai2:apache-${{ env.kimai_version }} - push: true - - name: Development image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . file: Dockerfile diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index edf0a1d5..4ad9ad6f 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -4,32 +4,37 @@ on: push: branches: - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + jobs: frontend: runs-on: ubuntu-latest - name: Frontend verification steps: + - name: Clone Kimai + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - name: Clone Kimai - uses: actions/checkout@v6 - with: - persist-credentials: false + - name: Setup PNPM + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 + with: + run_install: false - - name: Setup PNPM - uses: pnpm/action-setup@v6 - with: - run_install: false + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml + - name: Install frontend dependencies + run: pnpm install --frozen-lockfile --ignore-scripts - - name: Install frontend dependencies - run: pnpm install --frozen-lockfile --ignore-scripts - - - name: Check for security issues in frontend dependencies - run: pnpm audit + - name: Check for security issues in frontend dependencies + run: pnpm audit diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml new file mode 100644 index 00000000..35e0e66e --- /dev/null +++ b/.github/workflows/linting.yaml @@ -0,0 +1,76 @@ +name: Lint PHP + +on: + pull_request: null + push: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + integration: + name: Linting (${{ matrix.php }}) + runs-on: ubuntu-latest + + strategy: + matrix: + php: ['8.2'] # use lowest supported PHP version to prevent introducing syntax from newer PHP versions + + steps: + + - name: Clone Kimai + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup PHP + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 + with: + php-version: ${{ matrix.php }} + coverage: pcov + extensions: ctype, gd, iconv, intl, mbstring, xml, zip + tools: cs2pr, symfony-cli + env: + fail-fast: true + + - name: Determine composer cache directory + id: composer-cache + run: echo "composer_cache_directory=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache Composer dependencies + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: "${{ env.composer_cache_directory }}" + key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} + + - name: Install dependencies + run: composer install + + - name: Validate Composer + run: composer validate --strict --no-check-all + + - name: Lint YAML + run: APP_ENV=dev bin/console lint:yaml --parse-tags config + + - name: Lint XLIFF + run: APP_ENV=dev bin/console lint:xliff translations + + - name: Check codestyles + run: vendor/bin/php-cs-fixer fix --dry-run --verbose --config=.php-cs-fixer.dist.php --using-cache=no --show-progress=none --format=checkstyle | cs2pr + + - name: Run PHPStan for application + run: vendor/bin/phpstan analyse -c phpstan.neon --no-progress --error-format=checkstyle | cs2pr + + - name: Run PHPStan for tests + run: vendor/bin/phpstan analyse -c tests/phpstan.neon --no-progress --error-format=checkstyle | cs2pr + + - name: Lint codebase + run: composer linting + + - name: Check for security issues in packages + run: symfony security:check diff --git a/.github/workflows/lock-threads.yaml b/.github/workflows/lock-threads.yaml index 0cd892ba..eb6ebada 100644 --- a/.github/workflows/lock-threads.yaml +++ b/.github/workflows/lock-threads.yaml @@ -5,20 +5,22 @@ on: - cron: '17 1 * * *' workflow_dispatch: -permissions: - issues: write - pull-requests: write +permissions: {} concurrency: group: lock-threads + cancel-in-progress: true jobs: action: + permissions: + issues: write # needed to comment and close the issues runs-on: ubuntu-latest + name: Lock inactive issues steps: - - uses: dessant/lock-threads@v6 + - uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6.0.2 with: - process-only: 'issues, prs' + process-only: 'issues' github-token: ${{ secrets.GITHUB_TOKEN }} issue-inactive-days: '90' issue-comment: > diff --git a/.github/workflows/lockfiles.yaml b/.github/workflows/lockfiles.yaml index 1a46030a..d6a9e320 100644 --- a/.github/workflows/lockfiles.yaml +++ b/.github/workflows/lockfiles.yaml @@ -1,21 +1,27 @@ name: Check .lock files -on: + +on: # zizmor: ignore[dangerous-triggers] using the target branch workflow prevents adding new trustedAuthors pull_request_target: null push: branches: - main -permissions: - pull-requests: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} jobs: lockfiles: + permissions: + pull-requests: read # read the PR author runs-on: ubuntu-latest name: Verify lock file integrity steps: - name: Prevent file change - uses: xalvarez/prevent-file-change-action@v3 + uses: xalvarez/prevent-file-change-action@dbc67c205c9ed02aa39c497b422c24f364c3e8dd # v3.0.1 with: githubToken: ${{ secrets.GITHUB_TOKEN }} pattern: .*\.lock$|^\.github\/.*$ - trustedAuthors: kevinpapst, dependabot + trustedAuthors: kevinpapst diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml index fe84279d..d96dd834 100644 --- a/.github/workflows/release-drafter.yaml +++ b/.github/workflows/release-drafter.yaml @@ -5,26 +5,29 @@ on: branches: - main -permissions: - contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} jobs: correct_repository: - permissions: - contents: none runs-on: ubuntu-latest + name: Verify repository steps: - name: fail on fork if: github.repository_owner != 'kimai' run: exit 1 update_release_draft: + name: Draft next release permissions: - contents: write # for release-drafter/release-drafter to create a github release - pull-requests: read + contents: write # to create a github release draft + pull-requests: read # to identify changes that occurred needs: correct_repository runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v7 + - uses: release-drafter/release-drafter@c2e2804cc59f45f57076a99af580d0fedb697927 # v7.3.0 env: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index b1fd1846..42ab458e 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -1,15 +1,24 @@ name: Tests + on: pull_request: null push: branches: - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + jobs: integration: + name: Integration (${{ matrix.php }}) runs-on: ubuntu-latest services: mysql: - image: mysql:latest + image: mysql@sha256:c36050afdca850f23cef85703f84c7531a5ae155a11b5ee1c60acb09937c4084 # 8.4.9 env: MYSQL_ALLOW_EMPTY_PASSWORD: false MYSQL_ROOT_PASSWORD: kimai @@ -17,20 +26,20 @@ jobs: ports: - 3306/tcp options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: matrix: php: ['8.2', '8.3', '8.4', '8.5'] - name: Integration (${{ matrix.php }}) steps: - name: Clone Kimai - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # 2.37.1 with: php-version: ${{ matrix.php }} coverage: pcov @@ -47,7 +56,7 @@ jobs: run: echo "composer_cache_directory=$(composer config cache-dir)" >> $GITHUB_ENV - name: Cache Composer dependencies - uses: actions/cache@v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: "${{ env.composer_cache_directory }}" key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} @@ -55,28 +64,11 @@ jobs: - name: Install dependencies run: composer install - - name: Validate Composer - run: composer validate --strict --no-check-all - - - name: Warmup cache - run: APP_ENV=dev bin/console kimai:reload -n - - - name: Check codestyles - run: vendor/bin/php-cs-fixer fix --dry-run --verbose --config=.php-cs-fixer.dist.php --using-cache=no --show-progress=none --format=checkstyle | cs2pr - - - name: Run PHPStan for application - run: vendor/bin/phpstan analyse -c phpstan.neon --no-progress --error-format=checkstyle | cs2pr - - - name: Run PHPStan for tests - run: vendor/bin/phpstan analyse -c tests/phpstan.neon --no-progress --error-format=checkstyle | cs2pr - - - name: Lint codebase - run: composer linting - - name: Install LDAP package (for tests) run: composer require laminas/laminas-ldap - name: Setup problem matchers (for PHPUnit) + # zizmor: ignore[template-injection] coming from the https://github.com/marketplace/actions/setup-php-action run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Run quick unit-tests @@ -104,7 +96,7 @@ jobs: - name: Upload code coverage if: matrix.php == '8.5' - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.xml @@ -120,6 +112,3 @@ jobs: DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35 APP_ENV: dev MAILER_URL: null://localhost - - - name: Check for security issues in packages - run: symfony security:check diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml index 5638262c..d8181bc6 100644 --- a/.github/workflows/website.yaml +++ b/.github/workflows/website.yaml @@ -1,42 +1,52 @@ name: 'Website update' + on: - workflow_dispatch: - inputs: - kimai_version: - description: 'Kimai version for the website' - required: true - release: - types: [released] + workflow_dispatch: + inputs: + kimai_version: + description: 'Kimai version for the website' + required: true + release: + types: [released] + +concurrency: + group: update-website + cancel-in-progress: true + +permissions: {} jobs: - build: - name: Trigger version update for website - runs-on: ubuntu-latest - steps: - - name: "Determine Version" - run: | - input="${{ github.event.inputs.kimai_version }}" + build: + name: Trigger version update for website + runs-on: ubuntu-latest + steps: + - name: "Determine Version" + env: + GITHUB_EVENT_INPUTS_KIMAI_VERSION: ${{ github.event.inputs.kimai_version }} + GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} + run: | + input="${GITHUB_EVENT_INPUTS_KIMAI_VERSION}" + + # Determine between manual trigger and release event + if [ -z "$input" ]; then + echo "No input provided, using release tag" + version="${GITHUB_EVENT_RELEASE_TAG_NAME}" + else + echo "Using input provided: $input" + version="$input" + fi + + echo "kimai_version=$version" >> $GITHUB_ENV + + if [[ ! $version =~ ^2\.(0|[1-9]*)(0?)\.(0|[0-9]*)(0?)$ ]]; then + echo "Invalid version number: $version" + exit 1 + fi - # Determine between manual trigger and release event - if [ -z "$input" ]; then - echo "No input provided, using release tag" - version="${{ github.event.release.tag_name }}" - else - echo "Using input provided: $input" - version="$input" - fi - - echo "kimai_version=$version" >> $GITHUB_ENV - - if [[ ! $version =~ ^2\.(0|[1-9]*)(0?)\.(0|[0-9]*)(0?)$ ]]; then - echo "Invalid version number: $version" - exit 1 - fi - - - name: Emit repository_dispatch - uses: peter-evans/repository-dispatch@v4 - with: - token: ${{ secrets.WEBSITE_ACCESS_TOKEN }} - repository: kimai/www.kimai.org - event-type: kimai_release - client-payload: '{"kimai_version": "${{ env.kimai_version }}"}' + - name: Emit repository_dispatch + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 + with: + token: ${{ secrets.WEBSITE_ACCESS_TOKEN }} + repository: kimai/www.kimai.org + event-type: kimai_release + client-payload: '{"kimai_version": "${{ env.kimai_version }}"}' diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml new file mode 100644 index 00000000..ad70c899 --- /dev/null +++ b/.github/workflows/zizmor.yaml @@ -0,0 +1,28 @@ +name: Actions Security Analysis + +on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + zizmor: + name: Scan workflows + runs-on: ubuntu-latest + permissions: + security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files. + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run zizmor 🌈 + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 diff --git a/Dockerfile b/Dockerfile index bde16deb..23b1c9c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,8 +24,9 @@ # Source base, one of: fpm, apache ARG BASE="fpm" -# Kimai branch/tag to run -ARG KIMAI="main" +# Kimai version label (used for OCI labels and the KIMAI env var inside the image). +# The actual source is read from the local build context, not fetched by version. +ARG KIMAI="dev" # Timezone for images ARG TIMEZONE="Europe/Berlin" @@ -217,20 +218,6 @@ COPY --from=php-ext-intl /usr/local/lib/php/extensions/no-debug-non-zts-20230831 # PHP extension opcache COPY --from=php-ext-opcache /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini -########################### -# fetch Kimai sources -########################### - -FROM alpine:latest AS git-prod -ARG KIMAI -ARG TIMEZONE -# the convention in the Kimai repository is: tags are always version numbers, branch names always start with a letter -# if the KIMAI variable starts with a number (e.g. 2.24.0) we assume its a tag, otherwise its a branch -RUN [[ $KIMAI =~ ^[0-9] ]] && export REF='tags' || export REF='heads' && \ - wget -O "/opt/kimai.tar.gz" "https://github.com/kimai/kimai/archive/refs/${REF}/${KIMAI}.tar.gz" && \ - tar -xpzf /opt/kimai.tar.gz -C /opt/ && \ - mv /opt/kimai-${KIMAI} /opt/kimai - ########################### # global base build ########################### @@ -260,7 +247,11 @@ COPY .docker/dbtest.php /dbtest.php COPY .docker/entrypoint.sh /entrypoint.sh ENV DATABASE_URL="mysql://kimai:kimai@127.0.0.1:3306/kimai?charset=utf8mb4&serverVersion=8.3" -ENV APP_SECRET=change_this_to_something_unique +# APP_SECRET is intentionally not set here. The entrypoint resolves it (user-provided +# via -e APP_SECRET=... wins; otherwise a unique value is generated and persisted to +# the var/data volume and mirrored into .env.local). Setting it as a Dockerfile ENV +# would create a real env var that always wins over .env*, breaking `docker exec` +# console invocations. # The default container name for nginx is nginx ENV TRUSTED_PROXIES=nginx,localhost,127.0.0.1 ENV MAILER_FROM=kimai@example.com @@ -283,15 +274,15 @@ CMD [ "/entrypoint.sh" ] # development build FROM base AS dev -# copy kimai develop source -COPY --from=git-prod --chown=www-data:www-data /opt/kimai /opt/kimai +# copy kimai source from local build context (see .dockerignore for what is excluded) +COPY --chown=www-data:www-data . /opt/kimai COPY .docker /assets # do the composer deps installation RUN \ export COMPOSER_HOME=/composer && \ composer --no-ansi install --working-dir=/opt/kimai --optimize-autoloader && \ - composer --no-ansi clearcache && \ composer --no-ansi require --working-dir=/opt/kimai laminas/laminas-ldap && \ + composer --no-ansi clearcache && \ cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini && \ chown -R www-data:www-data /opt/kimai /usr/local/etc/php/php.ini && \ mkdir -p /opt/kimai/var/logs && chmod 777 /opt/kimai/var/logs && \ @@ -304,15 +295,15 @@ ENV memory_limit=512M # the "prod" stage (production build) is configured as last stage in the file, as this is the default target in BuildKit FROM base AS prod -# copy kimai production source -COPY --from=git-prod --chown=www-data:www-data /opt/kimai /opt/kimai +# copy kimai source from local build context (see .dockerignore for what is excluded) +COPY --chown=www-data:www-data . /opt/kimai COPY .docker /assets # do the composer deps installation RUN \ export COMPOSER_HOME=/composer && \ composer --no-ansi install --working-dir=/opt/kimai --no-dev --optimize-autoloader && \ - composer --no-ansi clearcache && \ composer --no-ansi require --update-no-dev --working-dir=/opt/kimai laminas/laminas-ldap && \ + composer --no-ansi clearcache && \ cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && \ sed -i "s/expose_php = On/expose_php = Off/g" /usr/local/etc/php/php.ini && \ sed -i "s/;opcache.enable=1/opcache.enable=1/g" /usr/local/etc/php/php.ini && \ diff --git a/UPGRADING.md b/UPGRADING.md index b8f70657..53f42389 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -8,6 +8,17 @@ you can upgrade your Kimai installation to the latest stable release. Check below if there are more version specific steps required, which need to be executed after the normal update process. Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation. +## [2.58.0](https://github.com/kimai/kimai/releases/tag/2.58.0) + +The official Docker image no longer runs with the default `APP_SECRET=change_this_to_something_unique`. +If you did not explicitly set your own `APP_SECRET` (via `-e APP_SECRET=...` or your compose/environment +config), the container now generates a unique secret on first start and persists it as `var/data/.appsecret` +inside the `data` volume that the documented Docker setup already mounts. + +As a one-time effect of this upgrade, all existing sessions, "remember me" cookies and pending +password-reset links become invalid — every user has to log in again once. No manual action is required; +the container starts as before. It is recommended to configure your own `APP_SECRET` explicitly. + ## [2.56.0](https://github.com/kimai/kimai/releases/tag/2.56.0) The required minimum PHP version is now 8.2, read https://www.php.net/supported-versions.php diff --git a/assets/js/widgets/KimaiReloadPageWidget.js b/assets/js/widgets/KimaiReloadPageWidget.js index cc3a52f9..4f07b790 100644 --- a/assets/js/widgets/KimaiReloadPageWidget.js +++ b/assets/js/widgets/KimaiReloadPageWidget.js @@ -9,6 +9,8 @@ * [KIMAI] KimaiReloadPageWidget: a simple helper to reload the page on events */ +import { Tooltip } from 'bootstrap'; + export default class KimaiReloadPageWidget { constructor(events, fullReload) { @@ -48,8 +50,14 @@ export default class KimaiReloadPageWidget { response.text().then((text) => { const temp = document.createElement('div'); temp.innerHTML = text; + const oldContent = document.querySelector('section.content'); + // dispose all tooltips before replacing the content, otherwise an open tooltip + // would remain visible in the upper left corner after its anchor element is gone + oldContent.querySelectorAll('[data-toggle="tooltip"]').forEach((el) => { + Tooltip.getInstance(el)?.dispose(); + }); const newContent = temp.querySelector('section.content'); - document.querySelector('section.content').replaceWith(newContent); + oldContent.replaceWith(newContent); document.dispatchEvent(new Event('kimai.reloadPage')); this._hideOverlay(); }); diff --git a/composer.json b/composer.json index b47afb44..733f91bf 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "8.2.*||8.3.*||8.4.*||8.5.*", + "php": ">=8.2", "ext-gd": "*", "ext-intl": "*", "ext-json": "*", diff --git a/composer.lock b/composer.lock index bd4f6973..2bbe99c8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9408273b8cfa9c509c6e483245818e8e", + "content-hash": "fa13e2255a6ecd636351e12bf7b69792", "packages": [ { "name": "azuyalabs/yasumi", @@ -14691,7 +14691,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "8.2.*||8.3.*||8.4.*||8.5.*", + "php": ">=8.2", "ext-gd": "*", "ext-intl": "*", "ext-json": "*", diff --git a/config/packages/security.yaml b/config/packages/security.yaml index dd3f10ef..c8f9abe2 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -72,7 +72,9 @@ security: login_link: check_route: link_login_check - signature_properties: ['id'] + # 'password' binds the HMAC signature to the password hash, so a + # link becomes invalid as soon as the user changes the password + signature_properties: ['id', 'password'] lifetime: 900 max_uses: 3 diff --git a/config/services.yaml b/config/services.yaml index 2a31eca5..b65d2f53 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -58,9 +58,23 @@ services: arguments: $settings: '%kimai.config%' + # HTTP client used by mPDF to fetch remote resources (e.g. logos referenced + # from custom Twig invoice templates). Decorated with NoPrivateNetworkHttpClient + # so requests to private/loopback/link-local targets are blocked at the + # network layer — defense in depth for SSRF. + # @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + Symfony\Component\HttpClient\NoPrivateNetworkHttpClient: + arguments: + - '@http_client' + + App\Pdf\SafeRemoteContentClient: + arguments: + - '@Symfony\Component\HttpClient\NoPrivateNetworkHttpClient' + App\Pdf\MPdfConverter: arguments: $cacheDirectory: '%kernel.cache_dir%' + $httpClient: '@App\Pdf\SafeRemoteContentClient' App\Utils\FileHelper: arguments: diff --git a/phpstan.neon b/phpstan.neon index 9483ae33..78294865 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3707,16 +3707,6 @@ parameters: count: 1 path: src/Utils/Parsedown.php - - - message: "#^Method App\\\\Utils\\\\ParsedownExtension\\:\\:inlineUrl\\(\\) has parameter \\$Excerpt with no type specified\\.$#" - count: 1 - path: src/Utils/ParsedownExtension.php - - - - message: "#^Method App\\\\Utils\\\\ParsedownExtension\\:\\:inlineUrl\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Utils/ParsedownExtension.php - - message: "#^Parameter \\#1 \\$str of function strtr expects string, string\\|null given\\.$#" count: 1 diff --git a/public/build/app.4f8430f7.js b/public/build/app.4f8430f7.js new file mode 100644 index 00000000..25ef5af4 --- /dev/null +++ b/public/build/app.4f8430f7.js @@ -0,0 +1,2 @@ +/*! For license information please see app.4f8430f7.js.LICENSE.txt */ +(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[524],{7368:function(t,e,n){n(3829),n(6833),n.g.KimaiPaginatedBoxWidget=n(7648).A,n.g.KimaiReloadPageWidget=n(1630).A,n.g.KimaiColor=n(9790).A,n.g.KimaiStorage=n(4667).A},6833:function(t,e,n){"use strict";var i=n(2647);class r{constructor(t){this._translations=t}get(t){return this._translations[t]}has(t){return t in this._translations}}class o{constructor(t){this._configurations=t}get(t){return this._configurations[t]}has(t){return t in this._configurations}isRTL(){return"rtl"===this.get("direction")}getLanguage(){return this.get("locale").replace("_","-")}is24Hours(){return!!this.get("twentyFourHours")}getFirstDayOfWeek(t=!0){void 0===t&&(t=!0);let e=this.get("first_dow_iso");return t||(e%=7),e}}n(9690);class s{init(){}getId(){return null}setContainer(t){if(!(t instanceof a))throw new Error("Plugin was given an invalid KimaiContainer");this._core=t}getContainer(){return this._core}getConfiguration(t){return this.getContainer().getConfiguration().get(t)}getConfigurations(){return this.getContainer().getConfiguration()}getDateUtils(){return this.getPlugin("date")}getPlugin(t){return this.getContainer().getPlugin(t)}getTranslation(){return this.getContainer().getTranslation()}translate(t){return this.getTranslation().get(t)}escape(t){return this.getPlugin("escape").escapeForHtml(t)}trigger(t,e=null){this.getPlugin("event").trigger(t,e)}fetch(t,e={}){return this.getPlugin("fetch").fetch(t,e)}fetchForm(t,e={},n=null){n=n||t.getAttribute("action");const i=t.getAttribute("method").toUpperCase();if("GET"===i){const i=this.getPlugin("form").convertFormDataToQueryString(t,{},!0);n=n+(n.includes("?")?"&":"?")+i,e={method:"GET",...e}}else"POST"===i&&(e={method:"POST",body:new FormData(t),...e});return this.fetch(n,e)}isMobile(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)<576}}class a{constructor(t,e){if(!(t instanceof o))throw new Error("Configuration needs to a KimaiConfiguration instance");if(this._configuration=t,!(e instanceof r))throw new Error("Configuration needs to a KimaiTranslation instance");this._translation=e,this._plugins=[]}registerPlugin(t){if(!(t instanceof s))throw new Error("Invalid plugin given, needs to be a KimaiPlugin instance");return t.setContainer(this),this._plugins.push(t),t}getPlugin(t){for(let e of this._plugins)if(null!==e.getId()&&e.getId()===t)return e;throw new Error("Unknown plugin: "+t)}getPlugins(){return this._plugins}getTranslation(){return this._translation}getConfiguration(){return this._configuration}getUser(){return this.getPlugin("user")}}class l extends s{constructor(t){super(),this.dataAttribute=t}getId(){return"datatable-column-visibility"}init(){let t=document.querySelector("["+this.dataAttribute+"]");if(null!==t){this._id=t.getAttribute(this.dataAttribute),this._modal=document.getElementById("modal_"+this._id),this._modal.addEventListener("show.bs.modal",()=>{this._evaluateCheckboxes()}),this._modal.querySelector("button[data-type=save]").addEventListener("click",()=>{this._saveVisibility()}),this._modal.querySelector("button[data-type=reset]").addEventListener("click",t=>{this._resetVisibility(t.currentTarget)}),this._modal.querySelectorAll("input[name=datatable_profile]").forEach(t=>{t.addEventListener("change",()=>{const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("data-href")).then(()=>{localStorage.setItem("kimai_profile",t.getAttribute("value")),document.location.reload()}).catch(()=>{e.setAttribute("action",t.getAttribute("data-href")),e.submit()})})});for(let t of this._modal.querySelectorAll("form input[type=checkbox]"))t.addEventListener("change",()=>{this._changeVisibility(t.getAttribute("name"),t.checked)})}}_evaluateCheckboxes(){const t=this._modal.getElementsByTagName("form")[0],e=document.getElementsByClassName("datatable_"+this._id)[0];for(let n of e.getElementsByTagName("th")){const e=n.getAttribute("data-field");if(null===e)continue;const i=t.querySelector("input[name="+e+"]");null!==i&&(i.checked="none"!==window.getComputedStyle(n).display)}}_saveVisibility(){const t=this._modal.getElementsByTagName("form")[0];this.fetchForm(t).then(()=>{document.location.reload()}).catch(()=>{t.submit()})}_resetVisibility(t){const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("formaction")).then(()=>{document.location.reload()}).catch(()=>{e.setAttribute("action",t.getAttribute("formaction")),e.submit()})}_changeVisibility(t,e){for(const n of document.getElementsByClassName("datatable_"+this._id)){let i=null;for(let r of n.getElementsByClassName("col_"+t)){if(null===i){let t="-none",n="d-table-cell";e||(t="-table-cell",n="d-none"),i="",r.classList.forEach(function(e,n,r){-1===e.indexOf(t)&&(i+=" "+e)}),-1===i.indexOf(n)&&(i+=" "+n)}r.className=i}}}}var c=n(6318);class u extends s{init(){[].slice.call(document.querySelectorAll('[data-toggle="tooltip"]')).map(function(t){return new c.m_(t)});[...document.querySelectorAll(".offcanvas")].map(t=>new c.go(t));this.getContainer().getPlugin("form").activateForm("div.page-wrapper form"),this._registerModalAutofocus("#remote_form_modal"),this.overlay=null,document.addEventListener("kimai.reloadContent",t=>{if(null!==this.overlay)return;let e="div.page-wrapper";void 0!==t.detail&&null!==t.detail&&(e=t.detail);const n=document.createElement("div");n.innerHTML='
',this.overlay=n.firstElementChild,document.querySelector(e).append(this.overlay)}),document.addEventListener("kimai.reloadedContent",()=>{null!==this.overlay&&(this.overlay.remove(),this.overlay=null)})}_registerModalAutofocus(t){if(this.isMobile())return;const e=document.querySelector(t);null!==e&&e.addEventListener("shown.bs.modal",()=>{const t=e.querySelector("form");let n=t.querySelectorAll("[autofocus]");n.length<1&&(n=t.querySelectorAll("input[type=text],input[type=date],textarea,select")),n.length>0&&n[0].focus()})}}var d=n(837);n(6311);class h extends s{supportsForm(t){return!1}activateForm(t){}destroyForm(t){}}class p extends h{constructor(t){super(),this._selector=t}init(){window.disableLitepickerStyles=!0,this._pickers=[]}supportsForm(t){return!0}activateForm(t){const e=this.getConfigurations().getFirstDayOfWeek(!1),n=this.getConfigurations().getLanguage();let i={buttonText:{previousMonth:'',nextMonth:'',apply:this.translate("confirm"),cancel:this.translate("cancel")}};const r=[].slice.call(t.querySelectorAll(this._selector)).map(t=>(void 0===t.dataset.format&&console.log("Trying to bind litepicker to an element without data-format attribute"),void 0!==t.hasAttribute("min")&&(i={...i,minDate:t.getAttribute("min")}),void 0!==t.hasAttribute("max")&&(i={...i,maxDate:t.getAttribute("max")}),i={...i,format:t.dataset.format,showTooltip:!1,element:t,lang:n,autoRefresh:!0,firstDay:e,setup:e=>{e.on("preselect",(t,n)=>{e._wasPreselected=!0}),e.on("selected",(n,i)=>{void 0!==e._wasPreselected&&(t.dispatchEvent(new Event("change",{bubbles:!0})),delete e._wasPreselected)}),void 0!==e.backdrop&&document.body.appendChild(e.backdrop)}},[t,new d.Litepicker(this.prepareOptions(i))]));this._pickers=this._pickers.concat(r)}prepareOptions(t){return{...t,plugins:["mobilefriendly"]}}destroyForm(t){[].slice.call(t.querySelectorAll(this._selector)).map(t=>{for(let e=0;e{this.reloadDatatable()};for(let t of e.split(" "))document.addEventListener(t,n);document.addEventListener("pagination-change",n),document.addEventListener("filter-change",n)}registerContextMenu(t){f.A.createForDataTable(t)}reloadDatatable(){const t=this.getContainer().getPlugin("toolbar").getSelector(),e=document.querySelector(t),n=t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector(this._contentArea);document.querySelector(this._contentArea).replaceWith(n),this.registerContextMenu(this._selector),document.dispatchEvent(new Event("kimai.reloadedContent"))};document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this._contentArea})),null!==e?this.fetchForm(e).then(t=>{t.text().then(n)}).catch(()=>{e.submit()}):this.fetch(document.location).then(t=>{t.text().then(n)}).catch(()=>{document.location.reload()})}}class v extends s{constructor(t,e){super(),this._formSelector=t,this._actionClass=e}getId(){return"toolbar"}init(){const t=this.getSelector();this._registerPagination(t),this._registerSortableTables(t),this._registerAlternativeSubmitActions(t,this._actionClass),[].slice.call(document.querySelectorAll(t+" input")).map(e=>{e.addEventListener("change",e=>{switch(e.target.id){case"order":case"orderBy":case"page":break;default:document.querySelector(t+" input#page").value=1}}),this.triggerChange()}),[].slice.call(document.querySelectorAll(t+" select")).map(e=>{e.addEventListener("change",e=>{let n=!0;switch(e.target.id){case"customer":null!==document.querySelector(t+" select#project")&&(n=!1);break;case"project":null!==document.querySelector(t+" select#activity")&&(n=!1)}document.querySelector(t+" input#page").value=1,n&&this.triggerChange()})})}_registerAlternativeSubmitActions(t,e){document.addEventListener("click",function(n){let i=n.target;for(;null!==i&&"function"==typeof i.matches&&!i.matches("body");){if(i.classList.contains(e)){const e=document.querySelector(t);if(null===e)return;const r=e.getAttribute("action"),o=e.getAttribute("method");void 0!==i.dataset.target&&(e.target=i.dataset.target),e.action=i.href,void 0!==i.dataset.method&&(e.method=i.dataset.method),e.submit(),e.target="",e.action=r,e.method=o,n.preventDefault(),n.stopPropagation()}i=i.parentNode}})}_registerSortableTables(t){document.body.addEventListener("click",e=>{if(!e.target.matches("th.sortable"))return;let n="DESC",i=e.target.dataset.order;e.target.classList.contains("sorting_desc")&&(n="ASC"),document.querySelector(t+" #orderBy").value=i,document.querySelector(t+" #order").value=n,document.querySelector(t+" #orderBy").dispatchEvent(new Event("change")),document.querySelector(t+" #order").dispatchEvent(new Event("change")),document.dispatchEvent(new Event("filter-change"))})}_registerPagination(t){document.body.addEventListener("click",e=>{if(!(e.target.matches("ul.pagination li a")||null!==e.target.parentNode&&e.target.parentNode.matches("ul.pagination li a")))return;let n=document.querySelector(t+" input#page");if(null===n)return;let i=e.target;i.matches("a")||(i=i.parentNode),e.preventDefault(),e.stopPropagation();let r=i.href.split("/"),o=r[r.length-1];return/\d/.test(o)||(o=1),n.value=o,n.dispatchEvent(new Event("change")),document.dispatchEvent(new Event("pagination-change")),!1})}triggerChange(){document.dispatchEvent(new Event("toolbar-change"))}getSelector(){return this._formSelector}}class y extends s{getId(){return"api"}_headers(){const t=new Headers;return t.append("Content-Type","application/json"),t}get(t,e,n,i){if(void 0!==e){const n=new URLSearchParams(e).toString();""!==n&&(t=t+(t.includes("?")?"&":"?")+n)}void 0===i&&(i=t=>{this.handleError("An error occurred",t)}),this.fetch(t,{method:"GET",headers:this._headers()}).then(t=>{t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}post(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"POST",body:this._parseData(e),headers:this._headers()}).then(t=>{t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}patch(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"PATCH",body:this._parseData(e),headers:this._headers()}).then(t=>{204===t.statusCode?n():t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}delete(t,e,n){void 0===n&&(n=t=>{this.handleError("action.delete.error",t)}),this.fetch(t,{method:"DELETE",headers:this._headers()}).then(()=>{e()}).catch(t=>{n(t)})}_parseData(t){return"object"==typeof t?JSON.stringify(t):t}handleError(t,e){if(void 0===e.headers)return;const n=e.headers.get("content-type");n&&-1!==n.indexOf("application/json")?e.json().then(n=>{let i=n.message;if(400===e.status&&n.errors){let t=[""+i+""];if(n.errors.errors)for(let e of n.errors.errors)t.push(e);if(n.errors.children)for(let e in n.errors.children){let i=n.errors.children[e];if(void 0!==i.errors&&i.errors.length>0)for(let e of i.errors)t.push(e)}t.length>0&&(i=t)}this.getPlugin("alert").error(t,i)}):e.text().then(()=>{const n="["+e.statusCode+"] "+e.statusText;this.getPlugin("alert").error(t,n)})}}class b extends s{addClickHandler(t,e,n){document.body.addEventListener("click",i=>{let r=i.target;for(;null!==r;){const e=r.tagName.toUpperCase();if("BODY"===e)return;if(r.matches(t))break;if("A"===e||"BUTTON"===e||"INPUT"===e||"LABEL"===e)return;for(let t of n)if(r.matches(t))return;r=r.parentNode}if(null===r)return;if(r.isContentEditable||r.parentNode.isContentEditable)return;if(!r.matches(t))return;for(let t of n)if(r.matches(t))return;i.preventDefault(),i.stopPropagation();let o=r.dataset.href;null==o&&(o=r.href),null!=o&&""!==o&&e(o)})}}class _ extends b{constructor(t){super(),this._selector=t}init(){this.addClickHandler(this._selector,function(t){window.location=t},[])}}class w extends b{constructor(t,e){super(),this._selector=t,this._stopSelector=e}getId(){return"modal"}init(){this._isDirty=!1;const t=this._getModalElement();null!==t&&(t.addEventListener("hide.bs.modal",e=>{if(this._isDirty){if(null===t.querySelector(".modal-body .remote_modal_is_dirty_warning")){const e=this.translate("modal.dirty"),n=document.createElement("div");n.innerHTML='

'+e+"

",t.querySelector(".modal-body").prepend(n.firstElementChild)}e.preventDefault()}else this._isDirty=!1,document.dispatchEvent(new Event("modal-hide"))}),t.addEventListener("hidden.bs.modal",()=>{this.getContainer().getPlugin("form").destroyForm(this._getFormIdentifier()),t.querySelector(".modal-body").replaceWith("")}),t.addEventListener("show.bs.modal",()=>{document.dispatchEvent(new Event("modal-show"))}),this.addClickHandler(this._selector,t=>{this.openUrlInModal(t)},this._stopSelector))}_getModal(){return c.aF.getOrCreateInstance(this._getModalElement())}openUrlInModal(t,e){const n=new Headers;n.append("X-Requested-With","Kimai-Modal"),this.fetch(t,{method:"GET",redirect:"follow",headers:n}).then(e=>{if(e.ok)return e.text().then(t=>{this._openFormInModal(t)});window.location=t}).catch(n=>{null==e?window.location=t:e(n)})}_getFormIdentifier(){return"#remote_form_modal .modal-content form"}_getModalElement(){return document.getElementById("remote_form_modal")}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}_openFormInModal(t){const e=this._getFormIdentifier();let n=this._getModalElement();const i=document.createElement("div");i.innerHTML=t;const r=this._makeScriptExecutable(i.querySelector("#form_modal .modal-content"));if(null!==r){let t=n.querySelector(".modal-dialog"),o=i.querySelector(".modal-dialog").classList.contains("modal-lg");o&&!t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),!o&&t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),n.querySelector(".modal-content").replaceWith(r),[].slice.call(n.querySelectorAll('[data-bs-dismiss="modal"]')).map(t=>{t.addEventListener("click",()=>{this._isDirty=!1,this._getModal().hide()})}),this.getContainer().getPlugin("form").activateForm(e)}let o=i.querySelector("div.alert");null!==o&&n.querySelector(".modal-body").prepend(o);const s=document.querySelector(e);s.addEventListener("change",()=>{this._isDirty=!0}),s.addEventListener("submit",this._getEventHandler()),this._getModal().show()}_getEventHandler(){return void 0===this.eventHandler&&(this.eventHandler=t=>{const e=t.target;if(void 0!==e.target&&""!==e.target)return!0;const n=document.querySelector(this._getFormIdentifier()+" button[type=submit]");n.textContent=n.textContent+" …",n.disabled=!0;const i=e.dataset.formEvent,r=this.getContainer().getPlugin("event");t.preventDefault(),t.stopPropagation();const o=new Headers;o.append("X-Requested-With","Kimai-Modal");const s={headers:o};this.fetchForm(e,s).then(t=>{t.text().then(t=>{const e=document.createElement("div");e.innerHTML=t;let o=!1,s=!1,a=!1;n.textContent=n.textContent.replace(" …",""),n.disabled=!1;const l=e.querySelector("#form_modal .modal-content");null!==l&&(o=null!==l.querySelector(".is-invalid"),o||(o=null!==l.querySelector(".invalid-feedback")),s=null!==l.querySelector("ul.list-unstyled li.text-danger"),a=null!==e.querySelector("div.alert-danger")),o||s||a?this._openFormInModal(t):(r.trigger(i),this._isDirty=!1,this._getModal().hide())})}).catch(t=>{let i=e.dataset.msgError;null!=i&&""!==i||(i="action.update.error");this.getContainer().getPlugin("alert").error(i,t.message),setTimeout(()=>{n.textContent=n.textContent.replace(" …",""),n.disabled=!1},1500)})}),this.eventHandler}}class k extends s{constructor(){super(),this._selector=".ticktac-menu",this._selectorEmpty=".ticktac-menu-empty",this._favIconUrl=null}getId(){return"active-records"}init(){if(null===document.querySelector(this._selector))return;const t=()=>{this.reloadActiveRecords()};document.addEventListener("kimai.timesheetUpdate",t),document.addEventListener("kimai.timesheetDelete",t),document.addEventListener("kimai.activityUpdate",t),document.addEventListener("kimai.activityDelete",t),document.addEventListener("kimai.projectUpdate",t),document.addEventListener("kimai.projectDelete",t),document.addEventListener("kimai.customerUpdate",t),document.addEventListener("kimai.customerDelete",t),this._updateBrowserTitle=!!this.getConfiguration("updateBrowserTitle");const e=()=>{this._updateDuration()};this._updatesHandler=setInterval(e,1e4),document.addEventListener("kimai.timesheetUpdate",e),document.addEventListener("kimai.reloadedContent",e)}_updateDuration(){const t=document.querySelectorAll('[data-since]:not([data-since=""])');if(this._updateBrowserTitle&&this._changeFavicon(t.length>0),0===t.length)return void(this._updateBrowserTitle&&(void 0===document.body.dataset.title?this._updateBrowserTitle=!1:document.title=document.body.dataset.title));const e=this.getDateUtils();let n=[];for(const i of t){const t=e.formatDuration(i.dataset.since);void 0!==i.dataset.replacer&&null!==i.dataset.title&&"?"!==t&&n.push(t),i.textContent=t}0!==n.length&&this._updateBrowserTitle&&(document.title=n.shift())}_setEntries(t){const e=t.length>0;for(let t of document.querySelectorAll(this._selectorEmpty))t.style.display=e?"none":"inline-block";for(let n of document.querySelectorAll(this._selector)){if(n.style.display=e?"inline-block":"none",!e)for(let t of n.querySelectorAll("[data-since]"))t.dataset.since="";const i=n.querySelector(".ticktac-stop");e?(i&&(i.accesskey="s"),this._replaceInNode(n,t[0])):i&&(i.accesskey=null)}this._updateDuration()}_replaceInNode(t,e){const n=this.getDateUtils(),i=t.querySelectorAll("[data-replacer]");for(let r of i){const i=r.dataset.replacer;"url"===i?r.dataset.href=t.dataset.href.replace("000",e.id):"activity"===i?r.innerText=e.activity.name:"project"===i?r.innerText=e.project.name:"customer"===i?r.innerText=e.project.customer.name:"duration"===i&&(r.dataset.since=e.begin,r.innerText=n.formatDuration(e.duration))}}reloadActiveRecords(){const t=this.getContainer().getPlugin("api"),e=document.querySelector(this._selector).dataset.api;t.get(e,{},t=>{this._setEntries(t)})}_changeFavicon(t){const e=document.createElement("canvas"),n=document.getElementById("favicon");null===this._favIconUrl&&(this._favIconUrl=n.href);const i=n.cloneNode(!0);if(e.getContext&&i){const r=window.devicePixelRatio,o=document.createElement("img");e.height=e.width=16*r,o.onload=function(){const o=e.getContext("2d");if(o.drawImage(this,0,0,e.width,e.height),t){const t=5.5*r;o.fillStyle="rgb(182,57,57)",o.fillRect(e.width/2-t/2,e.height/2-t/2,t,t)}i.href=e.toDataURL("image/png"),n.remove(),document.head.appendChild(i)},o.src=this._favIconUrl}}}class T extends s{getId(){return"event"}trigger(t,e=null){if(""!==t)for(const n of t.split(" ")){let t=new Event(n);null!==e&&(t=new CustomEvent(n,{detail:e})),document.dispatchEvent(t)}}}class E extends s{constructor(t){super(),this._selector=t}init(){document.addEventListener("click",t=>{let e=t.target;for(;null!==e&&"function"==typeof e.matches&&!e.matches("body");){if(e.classList.contains(this._selector)){const n=e.dataset;let i=n.href;i||(i=e.getAttribute("href")),void 0!==n.question?this.getContainer().getPlugin("alert").question(n.question,t=>{t&&this._callApi(i,n)}):this._callApi(i,n),t.preventDefault(),t.stopPropagation()}e=e.parentNode}})}_callApi(t,e){const n=e.method,i=e.event,r=this.getContainer().getPlugin("api"),o=this.getContainer().getPlugin("event"),s=(this.getContainer().getPlugin("alert"),()=>{o.trigger(i),document.dispatchEvent(new CustomEvent("kimai.reloadedContent"))}),a=t=>{let n="action.update.error";void 0!==e.msgError&&(n=e.msgError),document.dispatchEvent(new CustomEvent("kimai.reloadedContent")),r.handleError(n,t)};let l={};if(void 0!==e.payload&&(l=e.payload),document.dispatchEvent(new CustomEvent("kimai.reloadContent")),"PATCH"===n)r.patch(t,l,s,a);else if("POST"===n){let e={};r.post(t,e,s,a)}else"DELETE"===n?r.delete(t,s,a):"GET"===n&&r.get(t,l,s,a)}}class S extends s{getId(){return"alert"}error(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t)),t=t.replace("%reason%",""),void 0===e&&(e=null),null!==e&&(n.has(e)&&(e=n.get(e)),Array.isArray(e)&&(e=e.join("
")));const i="alert_global_error",r=document.getElementById(i);null!==r&&c.aF.getOrCreateInstance(r).hide();const o='\n \n ";this._showModal(o)}warning(t){this._show("warning",t)}success(t){this._toast("success",t)}info(t){this._show("info",t)}_showModal(t){const e=document.body,n=document.createElement("template");n.innerHTML=t.trim();const i=n.content.firstChild;e.appendChild(i);const r=new c.aF(i);i.addEventListener("hidden.bs.modal",function(){e.removeChild(i)}),r.show()}_show(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));const i='\n \n ";this._showModal(i)}_mapClass(t){return"info"===t||"success"===t||"warning"===t||"danger"===t?t:"error"===t?"danger":"primary"}_toast(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));let i='';"success"===t?i='':"warning"===t?i='':"danger"!==t&&"error"!==t||(i='');const r='',o=document.getElementById("toast-container"),s=document.createElement("template");s.innerHTML=r.trim();const a=s.content.firstChild;o.appendChild(a);const l=new c.y8(a);a.addEventListener("hidden.bs.toast",function(){o.removeChild(a)}),l.show()}question(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t));const i=this._mapClass("info"),r='\n \n ",o=document.body,s=document.createElement("template");s.innerHTML=r.trim();const a=s.content.firstChild;o.appendChild(a),a.querySelector(".question-confirm").addEventListener("click",()=>{e(!0)}),a.querySelector(".question-cancel").addEventListener("click",()=>{e(!1)});const l=new c.aF(a);a.addEventListener("hidden.bs.modal",()=>{o.removeChild(a)}),l.show()}}function x(t,e){t.split(/\s+/).forEach(t=>{e(t)})}class D{constructor(){this._events={}}on(t,e){x(t,t=>{const n=this._events[t]||[];n.push(e),this._events[t]=n})}off(t,e){var n=arguments.length;0!==n?x(t,t=>{if(1===n)return void delete this._events[t];const i=this._events[t];void 0!==i&&(i.splice(i.indexOf(e),1),this._events[t]=i)}):this._events={}}trigger(t,...e){var n=this;x(t,t=>{const i=n._events[t];void 0!==i&&i.forEach(t=>{t.apply(n,e)})})}}const O=t=>(t=t.filter(Boolean)).length<2?t[0]||"":1==I(t)?"["+t.join("")+"]":"(?:"+t.join("|")+")",L=t=>{if(!A(t))return t.join("");let e="",n=0;const i=()=>{n>1&&(e+="{"+n+"}")};return t.forEach((r,o)=>{r!==t[o-1]?(i(),e+=r,n=1):n++}),i(),e},C=t=>{let e=Array.from(t);return O(e)},A=t=>new Set(t).size!==t.length,M=t=>(t+"").replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu,"\\$1"),I=t=>t.reduce((t,e)=>Math.max(t,N(e)),0),N=t=>Array.from(t).length,P=t=>{if(1===t.length)return[[t]];let e=[];const n=t.substring(1);return P(n).forEach(function(n){let i=n.slice(0);i[0]=t.charAt(0)+i[0],e.push(i),i=n.slice(0),i.unshift(t.charAt(0)),e.push(i)}),e},F=[[0,65535]];let j,R;const $={},q={"/":"⁄∕",0:"߀",a:"ⱥɐɑ",aa:"ꜳ",ae:"æǽǣ",ao:"ꜵ",au:"ꜷ",av:"ꜹꜻ",ay:"ꜽ",b:"ƀɓƃ",c:"ꜿƈȼↄ",d:"đɗɖᴅƌꮷԁɦ",e:"ɛǝᴇɇ",f:"ꝼƒ",g:"ǥɠꞡᵹꝿɢ",h:"ħⱨⱶɥ",i:"ɨı",j:"ɉȷ",k:"ƙⱪꝁꝃꝅꞣ",l:"łƚɫⱡꝉꝇꞁɭ",m:"ɱɯϻ",n:"ꞥƞɲꞑᴎлԉ",o:"øǿɔɵꝋꝍᴑ",oe:"œ",oi:"ƣ",oo:"ꝏ",ou:"ȣ",p:"ƥᵽꝑꝓꝕρ",q:"ꝗꝙɋ",r:"ɍɽꝛꞧꞃ",s:"ßȿꞩꞅʂ",t:"ŧƭʈⱦꞇ",th:"þ",tz:"ꜩ",u:"ʉ",v:"ʋꝟʌ",vy:"ꝡ",w:"ⱳ",y:"ƴɏỿ",z:"ƶȥɀⱬꝣ",hv:"ƕ"};for(let t in q){let e=q[t]||"";for(let n=0;nt.normalize(e),z=t=>Array.from(t).reduce((t,e)=>t+B(e),""),B=t=>(t=V(t).toLowerCase().replace(H,t=>$[t]||""),V(t,"NFC"));const W=t=>{const e={},n=(t,n)=>{const i=e[t]||new Set,r=new RegExp("^"+C(i)+"$","iu");n.match(r)||(i.add(M(n)),e[t]=i)};for(let e of function*(t){for(const[e,n]of t)for(let t=e;t<=n;t++){let e=String.fromCharCode(t),n=z(e);n!=e.toLowerCase()&&(n.length>3||0!=n.length&&(yield{folded:n,composed:e,code_point:t}))}}(t))n(e.folded,e.folded),n(e.folded,e.composed);return e},U=t=>{const e=W(t),n={};let i=[];for(let t in e){let r=e[t];r&&(n[t]=C(r)),t.length>1&&i.push(M(t))}i.sort((t,e)=>e.length-t.length);const r=O(i);return R=new RegExp("^"+r,"u"),n},Y=(t,e=1)=>(e=Math.max(e,t.length-1),O(P(t).map(t=>((t,e=1)=>{let n=0;return t=t.map(t=>(j[t]&&(n+=t.length),j[t]||t)),n>=e?L(t):""})(t,e)))),Z=(t,e=!0)=>{let n=t.length>1?1:0;return O(t.map(t=>{let i=[];const r=e?t.length():t.length()-1;for(let e=0;e{for(const n of e){if(n.start!=t.start||n.end!=t.end)continue;if(n.substrs.join("")!==t.substrs.join(""))continue;let e=t.parts;const i=t=>{for(const n of e){if(n.start===t.start&&n.substr===t.substr)return!1;if(1!=t.length&&1!=n.length){if(t.startn.start)return!0;if(n.startt.start)return!0}}return!1};if(!(n.parts.filter(i).length>0))return!0}return!1};class K{parts;substrs;start;end;constructor(){this.parts=[],this.substrs=[],this.start=0,this.end=0}add(t){t&&(this.parts.push(t),this.substrs.push(t.substr),this.start=Math.min(t.start,this.start),this.end=Math.max(t.end,this.end))}last(){return this.parts[this.parts.length-1]}length(){return this.parts.length}clone(t,e){let n=new K,i=JSON.parse(JSON.stringify(this.parts)),r=i.pop();for(const t of i)n.add(t);let o=e.substr.substring(0,t-r.start),s=o.length;return n.add({start:r.start,end:r.start+s,length:s,substr:o}),n}}const J=t=>{var e;void 0===j&&(j=U(e||F)),t=z(t);let n="",i=[new K];for(let e=0;e0){a=a.sort((t,e)=>t.length()-e.length());for(let t of a)G(t,i)||i.push(t)}else if(e>0&&1==l.size&&!l.has("3")){n+=Z(i,!1);let t=new K;const e=i[0];e&&t.add(e.last()),i=[t]}}return n+=Z(i,!0),n},X=(t,e)=>{if(t)return t[e]},Q=(t,e)=>{if(t){for(var n,i=e.split(".");(n=i.shift())&&(t=t[n]););return t}},tt=(t,e,n)=>{var i,r;return t?(t+="",null==e.regex||-1===(r=t.search(e.regex))?0:(i=e.string.length/t.length,0===r&&(i+=.5),i*n)):0},et=(t,e)=>{var n=t[e];if("function"==typeof n)return n;n&&!Array.isArray(n)&&(t[e]=[n])},nt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},it=(t,e)=>"number"==typeof t&&"number"==typeof e?t>e?1:t(e=z(e+"").toLowerCase())?1:e>t?-1:0;class rt{items;settings;constructor(t,e){this.items=t,this.settings=e||{diacritics:!0}}tokenize(t,e,n){if(!t||!t.length)return[];const i=[],r=t.split(/\s+/);var o;return n&&(o=new RegExp("^("+Object.keys(n).map(M).join("|")+"):(.*)$")),r.forEach(t=>{let n,r=null,s=null;o&&(n=t.match(o))&&(r=n[1],t=n[2]),t.length>0&&(s=this.settings.diacritics?J(t)||null:M(t),s&&e&&(s="\\b"+s)),i.push({string:t,regex:s?new RegExp(s,"iu"):null,field:r})}),i}getScoreFunction(t,e){var n=this.prepareSearch(t,e);return this._getScoreFunction(n)}_getScoreFunction(t){const e=t.tokens,n=e.length;if(!n)return function(){return 0};const i=t.options.fields,r=t.weights,o=i.length,s=t.getAttrFn;if(!o)return function(){return 1};const a=1===o?function(t,e){const n=i[0].field;return tt(s(e,n),t,r[n]||1)}:function(t,e){var n=0;if(t.field){const i=s(e,t.field);!t.regex&&i?n+=1/o:n+=tt(i,t,1)}else nt(r,(i,r)=>{n+=tt(s(e,r),t,i)});return n/o};return 1===n?function(t){return a(e[0],t)}:"and"===t.options.conjunction?function(t){var i,r=0;for(let n of e){if((i=a(n,t))<=0)return 0;r+=i}return r/n}:function(t){var i=0;return nt(e,e=>{i+=a(e,t)}),i/n}}getSortFunction(t,e){var n=this.prepareSearch(t,e);return this._getSortFunction(n)}_getSortFunction(t){var e,n=[];const i=this,r=t.options,o=!t.query&&r.sort_empty?r.sort_empty:r.sort;if("function"==typeof o)return o.bind(this);const s=function(e,n){return"$score"===e?n.score:t.getAttrFn(i.items[n.id],e)};if(o)for(let e of o)(t.query||"$score"!==e.field)&&n.push(e);if(t.query){e=!0;for(let t of n)if("$score"===t.field){e=!1;break}e&&n.unshift({field:"$score",direction:"desc"})}else n=n.filter(t=>"$score"!==t.field);return n.length?function(t,e){var i,r;for(let o of n){if(r=o.field,i=("desc"===o.direction?-1:1)*it(s(r,t),s(r,e)))return i}return 0}:null}prepareSearch(t,e){const n={};var i=Object.assign({},e);if(et(i,"sort"),et(i,"sort_empty"),i.fields){et(i,"fields");const t=[];i.fields.forEach(e=>{"string"==typeof e&&(e={field:e,weight:1}),t.push(e),n[e.field]="weight"in e?e.weight:1}),i.fields=t}return{options:i,query:t.toLowerCase().trim(),tokens:this.tokenize(t,i.respect_word_boundaries,n),total:0,items:[],weights:n,getAttrFn:i.nesting?Q:X}}search(t,e){var n,i,r=this;i=this.prepareSearch(t,e),e=i.options,t=i.query;const o=e.score||r._getScoreFunction(i);t.length?nt(r.items,(t,r)=>{n=o(t),(!1===e.filter||n>0)&&i.items.push({score:n,id:r})}):nt(r.items,(t,e)=>{i.items.push({score:1,id:e})});const s=r._getSortFunction(i);return s&&i.items.sort(s),i.total=i.items.length,"number"==typeof e.limit&&(i.items=i.items.slice(0,e.limit)),i}}const ot=t=>null==t?null:st(t),st=t=>"boolean"==typeof t?t?"1":"0":t+"",at=t=>(t+"").replace(/&/g,"&").replace(//g,">").replace(/"/g,"""),lt=(t,e)=>{var n;return function(i,r){var o=this;n&&(o.loading=Math.max(o.loading-1,0),clearTimeout(n)),n=setTimeout(function(){n=null,o.loadedSearches[i]=!0,t.call(o,i,r)},e)}},ct=(t,e,n)=>{var i,r=t.trigger,o={};for(i of(t.trigger=function(){var n=arguments[0];if(-1===e.indexOf(n))return r.apply(t,arguments);o[n]=arguments},n.apply(t,[]),t.trigger=r,e))i in o&&r.apply(t,o[i])},ut=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},dt=(t,e,n,i)=>{t.addEventListener(e,n,i)},ht=(t,e)=>!!e&&(!!e[t]&&1===(e.altKey?1:0)+(e.ctrlKey?1:0)+(e.shiftKey?1:0)+(e.metaKey?1:0)),pt=(t,e)=>{const n=t.getAttribute("id");return n||(t.setAttribute("id",e),e)},mt=t=>t.replace(/[\\"']/g,"\\$&"),ft=(t,e)=>{e&&t.append(e)},gt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},vt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},yt=t=>"string"==typeof t&&t.indexOf("<")>-1,bt=(t,e)=>{var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!1),t.dispatchEvent(n)},_t=(t,e)=>{Object.assign(t.style,e)},wt=(t,...e)=>{var n=Tt(e);(t=Et(t)).map(t=>{n.map(e=>{t.classList.add(e)})})},kt=(t,...e)=>{var n=Tt(e);(t=Et(t)).map(t=>{n.map(e=>{t.classList.remove(e)})})},Tt=t=>{var e=[];return gt(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Et=t=>(Array.isArray(t)||(t=[t]),t),St=(t,e,n)=>{if(!n||n.contains(t))for(;t&&t.matches;){if(t.matches(e))return t;t=t.parentNode}},xt=(t,e=0)=>e>0?t[t.length-1]:t[0],Dt=(t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n},Ot=(t,e)=>{gt(e,(e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)})},Lt=(t,e)=>{t.parentNode&&t.parentNode.replaceChild(e,t)},Ct=(t,e)=>{if(null===e)return;if("string"==typeof e){if(!e.length)return;e=new RegExp(e,"i")}const n=t=>3===t.nodeType?(t=>{var n=t.data.match(e);if(n&&t.data.length>0){var i=document.createElement("span");i.className="highlight";var r=t.splitText(n.index);r.splitText(n[0].length);var o=r.cloneNode(!0);return i.appendChild(o),Lt(r,i),1}return 0})(t):((t=>{1!==t.nodeType||!t.childNodes||/(script|style)/i.test(t.tagName)||"highlight"===t.className&&"SPAN"===t.tagName||Array.from(t.childNodes).forEach(t=>{n(t)})})(t),0);n(t)},At="undefined"!=typeof navigator&&/Mac/.test(navigator.userAgent)?"metaKey":"ctrlKey";var Mt={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:null,createOnBlur:!1,createFilter:null,clearAfterSelect:!1,highlight:!0,openOnFocus:!0,shouldOpen:null,maxOptions:50,maxItems:null,hideSelected:null,duplicates:!1,addPrecedence:!1,selectOnTab:!1,preload:null,allowEmptyOption:!1,refreshThrottle:300,loadThrottle:300,loadingClass:"loading",dataAttr:null,optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"ts-wrapper",controlClass:"ts-control",dropdownClass:"ts-dropdown",dropdownContentClass:"ts-dropdown-content",itemClass:"item",optionClass:"option",dropdownParent:null,controlInput:'',copyClassesToDropdown:!1,placeholder:null,hidePlaceholder:null,shouldLoad:function(t){return t.length>0},render:{}};function It(t,e){var n=Object.assign({},Mt,e),i=n.dataAttr,r=n.labelField,o=n.valueField,s=n.disabledField,a=n.optgroupField,l=n.optgroupLabelField,c=n.optgroupValueField,u=t.tagName.toLowerCase(),d=t.getAttribute("placeholder")||t.getAttribute("data-placeholder");if(!d&&!n.allowEmptyOption){let e=t.querySelector('option[value=""]');e&&(d=e.textContent)}var h={placeholder:d,options:[],optgroups:[],items:[],maxItems:null};return"select"===u?(()=>{var e,u=h.options,d={},p=1;let m=0;var f=t=>{var e=Object.assign({},t.dataset),n=i&&e[i];return"string"==typeof n&&n.length&&(e=Object.assign(e,JSON.parse(n))),e},g=(t,e)=>{var i=ot(t.value);if(null!=i&&(i||n.allowEmptyOption)){if(d.hasOwnProperty(i)){if(e){var l=d[i][a];l?Array.isArray(l)?l.push(e):d[i][a]=[l,e]:d[i][a]=e}}else{var c=f(t);c[r]=c[r]||t.textContent,c[o]=c[o]||i,c[s]=c[s]||t.disabled,c[a]=c[a]||e,c.$option=t,c.$order=c.$order||++m,d[i]=c,u.push(c)}t.selected&&h.items.push(i)}};h.maxItems=t.hasAttribute("multiple")?null:1,gt(t.children,t=>{var n,i,r;"optgroup"===(e=t.tagName.toLowerCase())?((r=f(n=t))[l]=r[l]||n.getAttribute("label")||"",r[c]=r[c]||p++,r[s]=r[s]||n.disabled,r.$order=r.$order||++m,h.optgroups.push(r),i=r[c],gt(n.children,t=>{g(t,i)})):"option"===e&&g(t)})})():(()=>{const e=t.getAttribute(i);if(e)h.options=JSON.parse(e),gt(h.options,t=>{h.items.push(t[o])});else{var s=t.value.trim()||"";if(!n.allowEmptyOption&&!s.length)return;const e=s.split(n.delimiter);gt(e,t=>{const e={};e[r]=t,e[o]=t,h.options.push(e)}),h.items=e}})(),Object.assign({},Mt,h,e)}var Nt=0;class Pt extends(function(t){return t.plugins={},class extends t{constructor(){super(...arguments),this.plugins={names:[],settings:{},requested:{},loaded:{}}}static define(e,n){t.plugins[e]={name:e,fn:n}}initializePlugins(t){var e,n;const i=this,r=[];if(Array.isArray(t))t.forEach(t=>{"string"==typeof t?r.push(t):(i.plugins.settings[t.name]=t.options,r.push(t.name))});else if(t)for(e in t)t.hasOwnProperty(e)&&(i.plugins.settings[e]=t[e],r.push(e));for(;n=r.shift();)i.require(n)}loadPlugin(e){var n=this,i=n.plugins,r=t.plugins[e];if(!t.plugins.hasOwnProperty(e))throw new Error('Unable to find "'+e+'" plugin');i.requested[e]=!0,i.loaded[e]=r.fn.apply(n,[n.plugins.settings[e]||{}]),i.names.push(e)}require(t){var e=this,n=e.plugins;if(!e.plugins.loaded.hasOwnProperty(t)){if(n.requested[t])throw new Error('Plugin has circular dependency ("'+t+'")');e.loadPlugin(t)}return n.loaded[t]}}}(D)){constructor(t,e){var n;super(),this.order=0,this.isOpen=!1,this.isDisabled=!1,this.isReadOnly=!1,this.isInvalid=!1,this.isValid=!0,this.isLocked=!1,this.isFocused=!1,this.isInputHidden=!1,this.isSetup=!1,this.ignoreFocus=!1,this.ignoreHover=!1,this.hasOptions=!1,this.lastValue="",this.caretPos=0,this.loading=0,this.loadedSearches={},this.activeOption=null,this.activeItems=[],this.optgroups={},this.options={},this.userOptions={},this.items=[],this.refreshTimeout=null,Nt++;var i=vt(t);if(i.tomselect)throw new Error("Tom Select already initialized on this element");i.tomselect=this,n=(window.getComputedStyle&&window.getComputedStyle(i,null)).getPropertyValue("direction");const r=It(i,e);this.settings=r,this.input=i,this.tabIndex=i.tabIndex||0,this.is_select_tag="select"===i.tagName.toLowerCase(),this.rtl=/rtl/i.test(n),this.inputId=pt(i,"tomselect-"+Nt),this.isRequired=i.required,this.sifter=new rt(this.options,{diacritics:r.diacritics}),r.mode=r.mode||(1===r.maxItems?"single":"multi"),"boolean"!=typeof r.hideSelected&&(r.hideSelected="multi"===r.mode),"boolean"!=typeof r.hidePlaceholder&&(r.hidePlaceholder="multi"!==r.mode);var o=r.createFilter;"function"!=typeof o&&("string"==typeof o&&(o=new RegExp(o)),o instanceof RegExp?r.createFilter=t=>o.test(t):r.createFilter=t=>this.settings.duplicates||!this.options[t]),this.initializePlugins(r.plugins),this.setupCallbacks(),this.setupTemplates();const s=vt("
"),a=vt("
"),l=this._render("dropdown"),c=vt('
'),u=this.input.getAttribute("class")||"",d=r.mode;var h;if(wt(s,r.wrapperClass,u,d),wt(a,r.controlClass),ft(s,a),wt(l,r.dropdownClass,d),r.copyClassesToDropdown&&wt(l,u),wt(c,r.dropdownContentClass),ft(l,c),vt(r.dropdownParent||s).appendChild(l),yt(r.controlInput)){h=vt(r.controlInput);gt(["autocorrect","autocapitalize","autocomplete","spellcheck","aria-label"],t=>{i.getAttribute(t)&&Ot(h,{[t]:i.getAttribute(t)})}),h.tabIndex=-1,a.appendChild(h),this.focus_node=h}else r.controlInput?(h=vt(r.controlInput),this.focus_node=h):(h=vt(""),this.focus_node=a);this.wrapper=s,this.dropdown=l,this.dropdown_content=c,this.control=a,this.control_input=h,this.setup()}setup(){const t=this,e=t.settings,n=t.control_input,i=t.dropdown,r=t.dropdown_content,o=t.wrapper,s=t.control,a=t.input,l=t.focus_node,c={passive:!0},u=t.inputId+"-ts-dropdown";Ot(r,{id:u}),Ot(l,{role:"combobox","aria-haspopup":"listbox","aria-expanded":"false","aria-controls":u});const d=pt(l,t.inputId+"-ts-control"),h="label[for='"+(t=>t.replace(/['"\\]/g,"\\$&"))(t.inputId)+"']",p=document.querySelector(h),m=t.focus.bind(t);if(p){dt(p,"click",m),Ot(p,{for:d});const e=pt(p,t.inputId+"-ts-label");Ot(l,{"aria-labelledby":e}),Ot(r,{"aria-labelledby":e})}if(o.style.width=a.style.width,o.style.minWidth=a.style.minWidth,o.style.maxWidth=a.style.maxWidth,t.plugins.names.length){const e="plugin-"+t.plugins.names.join(" plugin-");wt([o,i],e)}(null===e.maxItems||e.maxItems>1)&&t.is_select_tag&&Ot(a,{multiple:"multiple"}),e.placeholder&&Ot(n,{placeholder:e.placeholder}),!e.splitOn&&e.delimiter&&(e.splitOn=new RegExp("\\s*"+M(e.delimiter)+"+\\s*")),e.load&&e.loadThrottle&&(e.load=lt(e.load,e.loadThrottle)),dt(i,"mousemove",()=>{t.ignoreHover=!1}),dt(i,"mouseenter",e=>{var n=St(e.target,"[data-selectable]",i);n&&t.onOptionHover(e,n)},{capture:!0}),dt(i,"click",e=>{const n=St(e.target,"[data-selectable]");n&&(t.onOptionSelect(e,n),ut(e,!0))}),dt(s,"click",e=>{var i=St(e.target,"[data-ts-item]",s);i&&t.onItemSelect(e,i)?ut(e,!0):""==n.value&&(t.onClick(),ut(e,!0))}),dt(l,"keydown",e=>t.onKeyDown(e)),dt(n,"keypress",e=>t.onKeyPress(e)),dt(n,"input",e=>t.onInput(e)),dt(l,"blur",e=>t.onBlur(e)),dt(l,"focus",e=>t.onFocus(e)),dt(n,"paste",e=>t.onPaste(e));const f=e=>{const r=e.composedPath()[0];if(!o.contains(r)&&!i.contains(r))return t.isFocused&&t.blur(),void t.inputState();r==n&&t.isOpen?e.stopPropagation():ut(e,!0)},g=()=>{t.isOpen&&t.positionDropdown()},v=()=>{t.isValid&&(t.isValid=!1,t.isInvalid=!0,t.refreshState())};dt(a,"invalid",v),dt(document,"mousedown",f),dt(window,"scroll",g,c),dt(window,"resize",g,c),this._destroy=()=>{a.removeEventListener("invalid",v),document.removeEventListener("mousedown",f),window.removeEventListener("scroll",g),window.removeEventListener("resize",g),p&&p.removeEventListener("click",m)},this.revertSettings={innerHTML:a.innerHTML,tabIndex:a.tabIndex},a.tabIndex=-1,a.insertAdjacentElement("afterend",t.wrapper),t.sync(!1),e.items=[],delete e.optgroups,delete e.options,t.refreshItems(),t.close(!1),t.inputState(),t.isSetup=!0,a.disabled?t.disable():a.readOnly?t.setReadOnly(!0):t.enable(),t.on("change",this.onChange),wt(a,"tomselected","ts-hidden-accessible"),t.trigger("initialize"),!0===e.preload&&t.preload()}setupOptions(t=[],e=[]){this.addOptions(t),gt(e,t=>{this.registerOptionGroup(t)})}setupTemplates(){var t=this,e=t.settings.labelField,n=t.settings.optgroupLabelField,i={optgroup:t=>{let e=document.createElement("div");return e.className="optgroup",e.appendChild(t.options),e},optgroup_header:(t,e)=>'
'+e(t[n])+"
",option:(t,n)=>"
"+n(t[e])+"
",item:(t,n)=>"
"+n(t[e])+"
",option_create:(t,e)=>'
Add '+e(t.input)+"
",no_results:()=>'
No results found
',loading:()=>'
',not_loading:()=>{},dropdown:()=>"
"};t.settings.render=Object.assign({},i,t.settings.render)}setupCallbacks(){var t,e,n={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",item_select:"onItemSelect",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(t in n)(e=this.settings[n[t]])&&this.on(t,e)}sync(t=!0){const e=this,n=t?It(e.input,{delimiter:e.settings.delimiter,allowEmptyOption:e.settings.allowEmptyOption}):e.settings;e.setupOptions(n.options,n.optgroups),e.setValue(n.items||[],!0),e.lastQuery=null}onClick(){var t=this;if(t.activeItems.length>0)return t.clearActiveItems(),void t.focus();t.isFocused&&t.isOpen?t.blur():t.focus()}onMouseDown(){}onChange(){bt(this.input,"input"),bt(this.input,"change")}onPaste(t){var e=this;e.isInputHidden||e.isLocked?ut(t):e.settings.splitOn&&setTimeout(()=>{var t=e.inputValue();if(t.match(e.settings.splitOn)){var n=t.trim().split(e.settings.splitOn);gt(n,t=>{ot(t)&&(this.options[t]?e.addItem(t):e.createItem(t))})}},0)}onKeyPress(t){var e=this;if(!e.isLocked){var n=String.fromCharCode(t.keyCode||t.which);return e.settings.create&&"multi"===e.settings.mode&&n===e.settings.delimiter?(e.createItem(),void ut(t)):void 0}ut(t)}onKeyDown(t){var e=this;if(e.ignoreHover=!0,e.isLocked)9!==t.keyCode&&ut(t);else{switch(t.keyCode){case 65:if(ht(At,t)&&""==e.control_input.value)return ut(t),void e.selectAll();break;case 27:return e.isOpen&&(ut(t,!0),e.close()),void e.clearActiveItems();case 40:if(!e.isOpen&&e.hasOptions)e.open();else if(e.activeOption){let t=e.getAdjacent(e.activeOption,1);t&&e.setActiveOption(t)}return void ut(t);case 38:if(e.activeOption){let t=e.getAdjacent(e.activeOption,-1);t&&e.setActiveOption(t)}return void ut(t);case 13:return void(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):(e.settings.create&&e.createItem()||document.activeElement==e.control_input&&e.isOpen)&&ut(t));case 37:return void e.advanceSelection(-1,t);case 39:return void e.advanceSelection(1,t);case 9:return void(e.settings.selectOnTab&&(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):e.settings.create&&e.createItem()&&ut(t)));case 8:case 46:return void e.deleteSelection(t)}e.isInputHidden&&!ht(At,t)&&ut(t)}}onInput(t){if(this.isLocked)return;const e=this.inputValue();this.lastValue!==e&&(this.lastValue=e,""!=e?(this.refreshTimeout&&window.clearTimeout(this.refreshTimeout),this.refreshTimeout=((t,e)=>e>0?window.setTimeout(t,e):(t.call(null),null))(()=>{this.refreshTimeout=null,this._onInput()},this.settings.refreshThrottle)):this._onInput())}_onInput(){const t=this.lastValue;this.settings.shouldLoad.call(this,t)&&this.load(t),this.refreshOptions(),this.trigger("type",t)}onOptionHover(t,e){this.ignoreHover||this.setActiveOption(e,!1)}onFocus(t){var e=this,n=e.isFocused;if(e.isDisabled||e.isReadOnly)return e.blur(),void ut(t);e.ignoreFocus||(e.isFocused=!0,"focus"===e.settings.preload&&e.preload(),n||e.trigger("focus"),e.activeItems.length||(e.inputState(),e.refreshOptions(!!e.settings.openOnFocus)),e.refreshState())}onBlur(t){if(!1!==document.hasFocus()){var e=this;if(e.isFocused){e.isFocused=!1,e.ignoreFocus=!1;var n=()=>{e.close(),e.setActiveItem(),e.setCaret(e.items.length),e.trigger("blur")};e.settings.create&&e.settings.createOnBlur?e.createItem(null,n):n()}}}onOptionSelect(t,e){var n,i=this;e.parentElement&&e.parentElement.matches("[data-disabled]")||(e.classList.contains("create")?i.createItem(null,()=>{i.settings.closeAfterSelect?i.close():i.settings.clearAfterSelect&&i.setTextboxValue()}):void 0!==(n=e.dataset.value)&&(i.lastQuery=null,i.addItem(n),i.settings.closeAfterSelect?i.close():i.settings.clearAfterSelect&&i.setTextboxValue(),!i.settings.hideSelected&&t.type&&/click/.test(t.type)&&i.setActiveOption(e)))}canSelect(t){return!!(this.isOpen&&t&&this.dropdown_content.contains(t))}onItemSelect(t,e){var n=this;return!n.isLocked&&"multi"===n.settings.mode&&(ut(t),n.setActiveItem(e,t),!0)}canLoad(t){return!!this.settings.load&&!this.loadedSearches.hasOwnProperty(t)}load(t){const e=this;if(!e.canLoad(t))return;wt(e.wrapper,e.settings.loadingClass),e.loading++;const n=e.loadCallback.bind(e);e.settings.load.call(e,t,n)}loadCallback(t,e){const n=this;n.loading=Math.max(n.loading-1,0),n.lastQuery=null,n.clearActiveOption(),n.setupOptions(t,e),n.refreshOptions(n.isFocused&&!n.isInputHidden),n.loading||kt(n.wrapper,n.settings.loadingClass),n.trigger("load",t,e)}preload(){var t=this.wrapper.classList;t.contains("preloaded")||(t.add("preloaded"),this.load(""))}setTextboxValue(t=""){var e=this.control_input;e.value!==t&&(e.value=t,bt(e,"update"),this.lastValue=t)}getValue(){return this.is_select_tag&&this.input.hasAttribute("multiple")?this.items:this.items.join(this.settings.delimiter)}setValue(t,e){ct(this,e?[]:["change"],()=>{this.clear(e),this.addItems(t,e)})}setMaxItems(t){0===t&&(t=null),this.settings.maxItems=t,this.refreshState()}setActiveItem(t,e){var n,i,r,o,s,a,l=this;if("single"!==l.settings.mode){if(!t)return l.clearActiveItems(),void(l.isFocused&&l.inputState());if("click"===(n=e&&e.type.toLowerCase())&&ht("shiftKey",e)&&l.activeItems.length){for(a=l.getLastActive(),(r=Array.prototype.indexOf.call(l.control.children,a))>(o=Array.prototype.indexOf.call(l.control.children,t))&&(s=r,r=o,o=s),i=r;i<=o;i++)t=l.control.children[i],-1===l.activeItems.indexOf(t)&&l.setActiveItemClass(t);ut(e)}else"click"===n&&ht(At,e)||"keydown"===n&&ht("shiftKey",e)?t.classList.contains("active")?l.removeActiveItem(t):l.setActiveItemClass(t):(l.clearActiveItems(),l.setActiveItemClass(t));l.inputState(),l.isFocused||l.focus()}}setActiveItemClass(t){const e=this,n=e.control.querySelector(".last-active");n&&kt(n,"last-active"),wt(t,"active last-active"),e.trigger("item_select",t),-1==e.activeItems.indexOf(t)&&e.activeItems.push(t)}removeActiveItem(t){var e=this.activeItems.indexOf(t);this.activeItems.splice(e,1),kt(t,"active")}clearActiveItems(){kt(this.activeItems,"active"),this.activeItems=[]}setActiveOption(t,e=!0){t!==this.activeOption&&(this.clearActiveOption(),t&&(this.activeOption=t,Ot(this.focus_node,{"aria-activedescendant":t.getAttribute("id")}),Ot(t,{"aria-selected":"true"}),wt(t,"active"),e&&this.scrollToOption(t)))}scrollToOption(t,e){if(!t)return;const n=this.dropdown_content,i=n.clientHeight,r=n.scrollTop||0,o=t.offsetHeight,s=t.getBoundingClientRect().top-n.getBoundingClientRect().top+r;s+o>i+r?this.scroll(s-i+o,e):s{t.setActiveItemClass(e)}))}inputState(){var t=this;t.control.contains(t.control_input)&&(Ot(t.control_input,{placeholder:t.settings.placeholder}),t.activeItems.length>0||!t.isFocused&&t.settings.hidePlaceholder&&t.items.length>0?(t.setTextboxValue(),t.isInputHidden=!0):(t.settings.hidePlaceholder&&t.items.length>0&&Ot(t.control_input,{placeholder:""}),t.isInputHidden=!1),t.wrapper.classList.toggle("input-hidden",t.isInputHidden))}inputValue(){return this.control_input.value.trim()}focus(){var t=this;t.isDisabled||t.isReadOnly||(t.ignoreFocus=!0,t.control_input.offsetWidth?t.control_input.focus():t.focus_node.focus(),setTimeout(()=>{t.ignoreFocus=!1,t.onFocus()},0))}blur(){this.focus_node.blur(),this.onBlur()}getScoreFunction(t){return this.sifter.getScoreFunction(t,this.getSearchOptions())}getSearchOptions(){var t=this.settings,e=t.sortField;return"string"==typeof t.sortField&&(e=[{field:t.sortField}]),{fields:t.searchField,conjunction:t.searchConjunction,sort:e,nesting:t.nesting}}search(t){var e,n,i=this,r=this.getSearchOptions();if(i.settings.score&&"function"!=typeof(n=i.settings.score.call(i,t)))throw new Error('Tom Select "score" setting must be a function that returns a function');return t!==i.lastQuery?(i.lastQuery=t,/(.)\1{15,}/.test(t)&&(t=""),e=i.sifter.search(t,Object.assign(r,{score:n})),i.currentResults=e):e=Object.assign({},i.currentResults),i.settings.hideSelected&&(e.items=e.items.filter(t=>{let e=ot(t.id);return!(null!==e&&-1!==i.items.indexOf(e))})),e}refreshOptions(t=!0){var e,n,i,r,o,s,a,l,c,u;const d={},h=[];var p=this,m=p.inputValue();const f=m===p.lastQuery||""==m&&null==p.lastQuery;var g=p.search(m),v=null,y=p.settings.shouldOpen||!1,b=p.dropdown_content;f&&(v=p.activeOption)&&(c=v.closest("[data-group]")),r=g.items.length,"number"==typeof p.settings.maxOptions&&(r=Math.min(r,p.settings.maxOptions)),r>0&&(y=!0);const _=(t,e)=>{let n=d[t];if(void 0!==n){let t=h[n];if(void 0!==t)return[n,t.fragment]}let i=document.createDocumentFragment();return n=h.length,h.push({fragment:i,order:e,optgroup:t}),[n,i]};for(e=0;e0&&(u=u.cloneNode(!0),Ot(u,{id:a.$id+"-clone-"+n,"aria-selected":null}),u.classList.add("ts-cloned"),kt(u,"active"),p.activeOption&&p.activeOption.dataset.value==r&&c&&c.dataset.group===o.toString()&&(v=u)),l.appendChild(u),""!=o&&(d[o]=i)}}var k;p.settings.lockOptgroupOrder&&h.sort((t,e)=>t.order-e.order),a=document.createDocumentFragment(),gt(h,t=>{let e=t.fragment,n=t.optgroup;if(!e||!e.children.length)return;let i=p.optgroups[n];if(void 0!==i){let t=document.createDocumentFragment(),n=p.render("optgroup_header",i);ft(t,n),ft(t,e);let r=p.render("optgroup",{group:i,options:t});ft(a,r)}else ft(a,e)}),b.innerHTML="",ft(b,a),p.settings.highlight&&(k=b.querySelectorAll("span.highlight"),Array.prototype.forEach.call(k,function(t){var e=t.parentNode;e.replaceChild(t.firstChild,t),e.normalize()}),g.query.length&&g.tokens.length&>(g.tokens,t=>{Ct(b,t.regex)}));var T=t=>{let e=p.render(t,{input:m});return e&&(y=!0,b.insertBefore(e,b.firstChild)),e};if(p.loading?T("loading"):p.settings.shouldLoad.call(p,m)?0===g.items.length&&T("no_results"):T("not_loading"),(l=p.canCreate(m))&&(u=T("option_create")),p.hasOptions=g.items.length>0||l,y){if(g.items.length>0){if(v||"single"!==p.settings.mode||null==p.items[0]||(v=p.getOption(p.items[0])),!b.contains(v)){let t=0;u&&!p.settings.addPrecedence&&(t=1),v=p.selectable()[t]}}else u&&(v=u);t&&!p.isOpen&&(p.open(),p.scrollToOption(v,"auto")),p.setActiveOption(v)}else p.clearActiveOption(),t&&p.isOpen&&p.close(!1)}selectable(){return this.dropdown_content.querySelectorAll("[data-selectable]")}addOption(t,e=!1){const n=this;if(Array.isArray(t))return n.addOptions(t,e),!1;const i=ot(t[n.settings.valueField]);return null!==i&&!n.options.hasOwnProperty(i)&&(t.$order=t.$order||++n.order,t.$id=n.inputId+"-opt-"+t.$order,n.options[i]=t,n.lastQuery=null,e&&(n.userOptions[i]=e,n.trigger("option_add",i,t)),i)}addOptions(t,e=!1){gt(t,t=>{this.addOption(t,e)})}registerOption(t){return this.addOption(t)}registerOptionGroup(t){var e=ot(t[this.settings.optgroupValueField]);return null!==e&&(t.$order=t.$order||++this.order,this.optgroups[e]=t,e)}addOptionGroup(t,e){var n;e[this.settings.optgroupValueField]=t,(n=this.registerOptionGroup(e))&&this.trigger("optgroup_add",n,e)}removeOptionGroup(t){this.optgroups.hasOwnProperty(t)&&(delete this.optgroups[t],this.clearCache(),this.trigger("optgroup_remove",t))}clearOptionGroups(){this.optgroups={},this.clearCache(),this.trigger("optgroup_clear")}updateOption(t,e){const n=this;var i,r;const o=ot(t),s=ot(e[n.settings.valueField]);if(null===o)return;const a=n.options[o];if(null==a)return;if("string"!=typeof s)throw new Error("Value must be set in option data");const l=n.getOption(o),c=n.getItem(o);if(e.$order=e.$order||a.$order,delete n.options[o],n.uncacheValue(s),n.options[s]=e,l){if(n.dropdown_content.contains(l)){const t=n._render("option",e);Lt(l,t),n.activeOption===l&&n.setActiveOption(t)}l.remove()}c&&(-1!==(r=n.items.indexOf(o))&&n.items.splice(r,1,s),i=n._render("item",e),c.classList.contains("active")&&wt(i,"active"),Lt(c,i)),n.lastQuery=null}removeOption(t,e){const n=this;t=st(t),n.uncacheValue(t),delete n.userOptions[t],delete n.options[t],n.lastQuery=null,n.trigger("option_remove",t),n.removeItem(t,e)}clearOptions(t){const e=(t||this.clearFilter).bind(this);this.loadedSearches={},this.userOptions={},this.clearCache();const n={};gt(this.options,(t,i)=>{e(t,i)&&(n[i]=t)}),this.options=this.sifter.items=n,this.lastQuery=null,this.trigger("option_clear")}clearFilter(t,e){return this.items.indexOf(e)>=0}getOption(t,e=!1){const n=ot(t);if(null===n)return null;const i=this.options[n];if(null!=i){if(i.$div)return i.$div;if(e)return this._render("option",i)}return null}getAdjacent(t,e,n="option"){var i;if(!t)return null;i="item"==n?this.controlChildren():this.dropdown_content.querySelectorAll("[data-selectable]");for(let n=0;n0?i[n+1]:i[n-1];return null}getItem(t){if("object"==typeof t)return t;var e=ot(t);return null!==e?this.control.querySelector(`[data-value="${mt(e)}"]`):null}addItems(t,e){var n=this,i=Array.isArray(t)?t:[t];const r=(i=i.filter(t=>-1===n.items.indexOf(t)))[i.length-1];i.forEach(t=>{n.isPending=t!==r,n.addItem(t,e)})}addItem(t,e){ct(this,e?[]:["change","dropdown_close"],()=>{var n,i;const r=this,o=r.settings.mode,s=ot(t);if((!s||-1===r.items.indexOf(s)||("single"===o&&r.close(),"single"!==o&&r.settings.duplicates))&&null!==s&&r.options.hasOwnProperty(s)&&("single"===o&&r.clear(e),"multi"!==o||!r.isFull())){if(n=r._render("item",r.options[s]),r.control.contains(n)&&(n=n.cloneNode(!0)),i=r.isFull(),r.items.splice(r.caretPos,0,s),r.insertAtCaret(n),r.isSetup){if(!r.isPending&&r.settings.hideSelected){let t=r.getOption(s),e=r.getAdjacent(t,1);e&&r.setActiveOption(e)}r.settings.clearAfterSelect&&r.setTextboxValue(),r.isPending||r.settings.closeAfterSelect||r.refreshOptions(r.isFocused&&"single"!==o),0!=r.settings.closeAfterSelect&&r.isFull()?r.close():r.isPending||r.positionDropdown(),r.trigger("item_add",s,n),r.isPending||r.updateOriginalInput({silent:e})}(!r.isPending||!i&&r.isFull())&&(r.inputState(),r.refreshState())}})}removeItem(t=null,e){const n=this;if(!(t=n.getItem(t)))return;var i,r;const o=t.dataset.value;i=Dt(t),t.remove(),t.classList.contains("active")&&(r=n.activeItems.indexOf(t),n.activeItems.splice(r,1),kt(t,"active")),n.items.splice(i,1),n.lastQuery=null,!n.settings.persist&&n.userOptions.hasOwnProperty(o)&&n.removeOption(o,e),i{}){3===arguments.length&&(e=arguments[2]),"function"!=typeof e&&(e=()=>{});var n,i=this,r=i.caretPos;if(t=t||i.inputValue(),!i.canCreate(t)){return ot(t)&&this.options[t]&&i.addItem(t),e(),!1}i.lock();var o=!1,s=t=>{if(i.unlock(),!t||"object"!=typeof t)return e();var n=ot(t[i.settings.valueField]);if("string"!=typeof n)return e();i.setTextboxValue(),i.addOption(t,!0),i.setCaret(r),i.addItem(n),e(t),o=!0};return n="function"==typeof i.settings.create?i.settings.create.call(this,t,s):{[i.settings.labelField]:t,[i.settings.valueField]:t},o||s(n),!0}refreshItems(){var t=this;t.lastQuery=null,t.isSetup&&t.addItems(t.items),t.updateOriginalInput(),t.refreshState()}refreshState(){const t=this;t.refreshValidityState();const e=t.isFull(),n=t.isLocked;t.wrapper.classList.toggle("rtl",t.rtl);const i=t.wrapper.classList;var r;i.toggle("focus",t.isFocused),i.toggle("disabled",t.isDisabled),i.toggle("readonly",t.isReadOnly),i.toggle("required",t.isRequired),i.toggle("invalid",!t.isValid),i.toggle("locked",n),i.toggle("full",e),i.toggle("input-active",t.isFocused&&!t.isInputHidden),i.toggle("dropdown-active",t.isOpen),i.toggle("has-options",(r=t.options,0===Object.keys(r).length)),i.toggle("has-items",t.items.length>0)}refreshValidityState(){var t=this;t.input.validity&&(t.isValid=t.input.validity.valid,t.isInvalid=!t.isValid)}isFull(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems}updateOriginalInput(t={}){const e=this;var n,i;const r=e.input.querySelector('option[value=""]');if(e.is_select_tag){const o=[],s=e.input.querySelectorAll("option:checked").length;function a(t,n,i){return t||(t=vt('")),t!=r&&e.input.append(t),o.push(t),(t!=r||s>0)&&(t.selected=!0),t}e.input.querySelectorAll("option:checked").forEach(t=>{t.selected=!1}),0==e.items.length&&"single"==e.settings.mode?a(r,"",""):e.items.forEach(t=>{if(n=e.options[t],i=n[e.settings.labelField]||"",o.includes(n.$option)){a(e.input.querySelector(`option[value="${mt(t)}"]:not(:checked)`),t,i)}else n.$option=a(n.$option,t,i)})}else e.input.value=e.getValue();e.isSetup&&(t.silent||e.trigger("change",e.getValue()))}open(){var t=this;t.isLocked||t.isOpen||"multi"===t.settings.mode&&t.isFull()||(t.isOpen=!0,Ot(t.focus_node,{"aria-expanded":"true"}),t.refreshState(),_t(t.dropdown,{visibility:"hidden",display:"block"}),t.positionDropdown(),_t(t.dropdown,{visibility:"visible",display:"block"}),t.focus(),t.trigger("dropdown_open",t.dropdown))}close(t=!0){var e=this,n=e.isOpen;t&&(e.setTextboxValue(),"single"===e.settings.mode&&e.items.length&&e.inputState()),e.isOpen=!1,Ot(e.focus_node,{"aria-expanded":"false"}),_t(e.dropdown,{display:"none"}),e.settings.hideSelected&&e.clearActiveOption(),e.refreshState(),n&&e.trigger("dropdown_close",e.dropdown)}positionDropdown(){if("body"===this.settings.dropdownParent){var t=this.control,e=t.getBoundingClientRect(),n=t.offsetHeight+e.top+window.scrollY,i=e.left+window.scrollX;_t(this.dropdown,{width:e.width+"px",top:n+"px",left:i+"px"})}}clear(t){var e=this;if(e.items.length){var n=e.controlChildren();gt(n,t=>{e.removeItem(t,!0)}),e.inputState(),t||e.updateOriginalInput(),e.trigger("clear")}}insertAtCaret(t){const e=this,n=e.caretPos,i=e.control;i.insertBefore(t,i.children[n]||null),e.setCaret(n+1)}deleteSelection(t){var e,n,i,r,o,s=this;e=t&&8===t.keyCode?-1:1,n={start:(o=s.control_input).selectionStart||0,length:(o.selectionEnd||0)-(o.selectionStart||0)};const a=[];if(s.activeItems.length)r=xt(s.activeItems,e),i=Dt(r),e>0&&i++,gt(s.activeItems,t=>a.push(t));else if((s.isFocused||"single"===s.settings.mode)&&s.items.length){const t=s.controlChildren();let i;e<0&&0===n.start&&0===n.length?i=t[s.caretPos-1]:e>0&&n.start===s.inputValue().length&&(i=t[s.caretPos]),void 0!==i&&a.push(i)}if(!s.shouldDelete(a,t))return!1;for(ut(t,!0),void 0!==i&&s.setCaret(i);a.length;)s.removeItem(a.pop());return s.inputState(),s.positionDropdown(),s.refreshOptions(!1),!0}shouldDelete(t,e){const n=t.map(t=>t.dataset.value);return!(!n.length||"function"==typeof this.settings.onDelete&&!1===this.settings.onDelete.call(this,n,e))}advanceSelection(t,e){var n,i,r=this;r.rtl&&(t*=-1),r.inputValue().length||(ht(At,e)||ht("shiftKey",e)?(i=(n=r.getLastActive(t))?n.classList.contains("active")?r.getAdjacent(n,t,"item"):n:t>0?r.control_input.nextElementSibling:r.control_input.previousElementSibling)&&(i.classList.contains("active")&&r.removeActiveItem(n),r.setActiveItemClass(i)):r.moveCaret(t))}moveCaret(t){}getLastActive(t){let e=this.control.querySelector(".last-active");if(e)return e;var n=this.control.querySelectorAll(".active");return n?xt(n,t):void 0}setCaret(t){this.caretPos=this.items.length}controlChildren(){return Array.from(this.control.querySelectorAll("[data-ts-item]"))}lock(){this.setLocked(!0)}unlock(){this.setLocked(!1)}setLocked(t=this.isReadOnly||this.isDisabled){this.isLocked=t,this.refreshState()}disable(){this.setDisabled(!0),this.close()}enable(){this.setDisabled(!1)}setDisabled(t){this.focus_node.tabIndex=t?-1:this.tabIndex,this.isDisabled=t,this.input.disabled=t,this.control_input.disabled=t,this.setLocked()}setReadOnly(t){this.isReadOnly=t,this.input.readOnly=t,this.control_input.readOnly=t,this.setLocked()}destroy(){var t=this,e=t.revertSettings;t.trigger("destroy"),t.off(),t.wrapper.remove(),t.dropdown.remove(),t.input.innerHTML=e.innerHTML,t.input.tabIndex=e.tabIndex,kt(t.input,"tomselected","ts-hidden-accessible"),t._destroy(),delete t.input.tomselect}render(t,e){var n,i;const r=this;if("function"!=typeof this.settings.render[t])return null;if(!(i=r.settings.render[t].call(this,e,at)))return null;if(i=vt(i),"option"===t||"option_create"===t?e[r.settings.disabledField]?Ot(i,{"aria-disabled":"true"}):Ot(i,{"data-selectable":""}):"optgroup"===t&&(n=e.group[r.settings.optgroupValueField],Ot(i,{"data-group":n}),e.group[r.settings.disabledField]&&Ot(i,{"data-disabled":""})),"option"===t||"item"===t){const n=st(e[r.settings.valueField]);Ot(i,{"data-value":n}),"item"===t?(wt(i,r.settings.itemClass),Ot(i,{"data-ts-item":""})):(wt(i,r.settings.optionClass),Ot(i,{role:"option",id:e.$id}),e.$div=i,r.options[n]=e)}return i}_render(t,e){const n=this.render(t,e);if(null==n)throw"HTMLElement expected";return n}clearCache(){gt(this.options,t=>{t.$div&&(t.$div.remove(),delete t.$div)})}uncacheValue(t){const e=this.getOption(t);e&&e.remove()}canCreate(t){return this.settings.create&&t.length>0&&this.settings.createFilter.call(this,t)}hook(t,e,n){var i=this,r=i[e];i[e]=function(){var e,o;return"after"===t&&(e=r.apply(i,arguments)),o=n.apply(i,arguments),"instead"===t?o:("before"===t&&(e=r.apply(i,arguments)),e)}}}const Ft=t=>"boolean"==typeof t?t?"1":"0":t+"",jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Rt=t=>"string"==typeof t&&t.indexOf("<")>-1;const $t=t=>"string"==typeof t&&t.indexOf("<")>-1;const qt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Ht=t=>"string"==typeof t&&t.indexOf("<")>-1,Vt=(t,e)=>{((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(e,(e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)})};const zt=t=>"string"==typeof t&&t.indexOf("<")>-1;const Bt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Wt=t=>(Array.isArray(t)||(t=[t]),t);const Ut=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},Yt=t=>"string"==typeof t&&t.indexOf("<")>-1,Zt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Gt=t=>(Array.isArray(t)||(t=[t]),t);const Kt=(t,e,n,i)=>{t.addEventListener(e,n,i)};const Jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Xt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Qt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(te(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},te=t=>"string"==typeof t&&t.indexOf("<")>-1;const ee=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},ne=t=>(Array.isArray(t)||(t=[t]),t);Pt.define("change_listener",function(){var t,e,n,i;t=this.input,e="change",n=()=>{this.sync()},t.addEventListener(e,n,i)}),Pt.define("checkbox_options",function(t){var e=this,n=e.onOptionSelect;e.settings.hideSelected=!1;const i=Object.assign({className:"tomselect-checkbox",checkedClassNames:void 0,uncheckedClassNames:void 0},t);var r=function(t,e){e?(t.checked=!0,i.uncheckedClassNames&&t.classList.remove(...i.uncheckedClassNames),i.checkedClassNames&&t.classList.add(...i.checkedClassNames)):(t.checked=!1,i.checkedClassNames&&t.classList.remove(...i.checkedClassNames),i.uncheckedClassNames&&t.classList.add(...i.uncheckedClassNames))},o=function(t){setTimeout(()=>{var e=t.querySelector("input."+i.className);e instanceof HTMLInputElement&&r(e,t.classList.contains("selected"))},1)};e.hook("after","setupTemplates",()=>{var t=e.settings.render.option;e.settings.render.option=(n,o)=>{var s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Rt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(t.call(e,n,o)),a=document.createElement("input");i.className&&a.classList.add(i.className),a.addEventListener("click",function(t){jt(t)}),a.type="checkbox";const l=null==(c=n[e.settings.valueField])?null:Ft(c);var c;return r(a,!!(l&&e.items.indexOf(l)>-1)),s.prepend(a),s}}),e.on("item_remove",t=>{var n=e.getOption(t);n&&(n.classList.remove("selected"),o(n))}),e.on("item_add",t=>{var n=e.getOption(t);n&&o(n)}),e.hook("instead","onOptionSelect",(t,i)=>{if(i.classList.contains("selected"))return i.classList.remove("selected"),e.removeItem(i.dataset.value),e.refreshOptions(),void jt(t,!0);n.call(e,t,i),o(i)})}),Pt.define("clear_button",function(t){const e=this,n=Object.assign({className:"clear-button",title:"Clear All",role:"button",tabindex:0,html:t=>`
×
`},t);e.on("initialize",()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if($t(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n));t.addEventListener("click",t=>{e.isLocked||(e.clear(),"single"===e.settings.mode&&e.settings.allowEmptyOption&&e.addItem(""),e.refreshOptions(!1),t.preventDefault(),t.stopPropagation())}),e.control.appendChild(t)})}),Pt.define("drag_drop",function(){var t=this;if("multi"!==t.settings.mode)return;var e=t.lock,n=t.unlock;let i,r=!0;t.hook("after","setupTemplates",()=>{var e=t.settings.render.item;t.settings.render.item=(n,o)=>{const s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Ht(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(e.call(t,n,o));Vt(s,{draggable:"true"});const a=t=>{t.preventDefault(),s.classList.add("ts-drag-over"),l(s,i)},l=(t,e)=>{var n,i,r;void 0!==e&&(((t,e)=>{do{var n;if(t==(e=null==(n=e)?void 0:n.previousElementSibling))return!0}while(e&&e.previousElementSibling);return!1})(e,s)?(i=e,null==(r=(n=t).parentNode)||r.insertBefore(i,n.nextSibling)):((t,e)=>{var n;null==(n=t.parentNode)||n.insertBefore(e,t)})(t,e))};return qt(s,"mousedown",t=>{r||((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t),t.stopPropagation()}),qt(s,"dragstart",t=>{i=s,setTimeout(()=>{s.classList.add("ts-dragging")},0)}),qt(s,"dragenter",a),qt(s,"dragover",a),qt(s,"dragleave",()=>{s.classList.remove("ts-drag-over")}),qt(s,"dragend",()=>{var e;document.querySelectorAll(".ts-drag-over").forEach(t=>t.classList.remove("ts-drag-over")),null==(e=i)||e.classList.remove("ts-dragging"),i=void 0;var n=[];t.control.querySelectorAll("[data-value]").forEach(t=>{if(t.dataset.value){let e=t.dataset.value;e&&n.push(e)}}),t.setValue(n)}),s}}),t.hook("instead","lock",()=>(r=!1,e.call(t))),t.hook("instead","unlock",()=>(r=!0,n.call(t)))}),Pt.define("dropdown_header",function(t){const e=this,n=Object.assign({title:"Untitled",headerClass:"dropdown-header",titleRowClass:"dropdown-header-title",labelClass:"dropdown-header-label",closeClass:"dropdown-header-close",html:t=>'
'+t.title+'×
'},t);e.on("initialize",()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(zt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n)),i=t.querySelector("."+n.closeClass);i&&i.addEventListener("click",t=>{((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t,!0),e.close()}),e.dropdown.insertBefore(t,e.dropdown.firstChild)})}),Pt.define("caret_position",function(){var t=this;t.hook("instead","setCaret",e=>{"single"!==t.settings.mode&&t.control.contains(t.control_input)?(e=Math.max(0,Math.min(t.items.length,e)))==t.caretPos||t.isPending||t.controlChildren().forEach((n,i)=>{i{if(!t.isFocused)return;const n=t.getLastActive(e);if(n){const i=((t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n})(n);t.setCaret(e>0?i+1:i),t.setActiveItem(),((t,...e)=>{var n=Bt(e);(t=Wt(t)).map(t=>{n.map(e=>{t.classList.remove(e)})})})(n,"last-active")}else t.setCaret(t.caretPos+e)})}),Pt.define("dropdown_input",function(){const t=this;t.settings.shouldOpen=!0,t.hook("before","setup",()=>{var e;t.focus_node=t.control,((t,...e)=>{var n=Zt(e);(t=Gt(t)).map(t=>{n.map(e=>{t.classList.add(e)})})})(t.control_input,"dropdown-input");const n=Ut('");for(var S=1;S<=7;S+=1){var x=3+this.options.firstDay+S,D=document.createElement("div");D.innerHTML=this.weekdayName(x),D.title=this.weekdayName(x,"long"),E.appendChild(D)}var O=document.createElement("div");O.className=a.containerDays;var L=this.calcSkipDays(i);this.options.showWeekNumbers&&L&&O.appendChild(this.renderWeekNumber(i));for(var C=0;C1&&1===this.datePicked.length){var r=this.options.minDays-1,o=this.datePicked[0].clone().subtract(r,"day"),c=this.datePicked[0].clone().add(r,"day");t.isBetween(o,this.datePicked[0],"(]")&&e.classList.add(a.isLocked),t.isBetween(this.datePicked[0],c,"[)")&&e.classList.add(a.isLocked)}if(this.options.maxDays&&1===this.datePicked.length){var u=this.options.maxDays;o=this.datePicked[0].clone().subtract(u,"day"),c=this.datePicked[0].clone().add(u,"day"),t.isSameOrBefore(o)&&e.classList.add(a.isLocked),t.isSameOrAfter(c)&&e.classList.add(a.isLocked)}return this.options.selectForward&&1===this.datePicked.length&&t.isBefore(this.datePicked[0])&&e.classList.add(a.isLocked),this.options.selectBackward&&1===this.datePicked.length&&t.isAfter(this.datePicked[0])&&e.classList.add(a.isLocked),l.dateIsLocked(t,this.options,this.datePicked)&&e.classList.add(a.isLocked),this.options.highlightedDays.length&&this.options.highlightedDays.filter(function(e){return e instanceof Array?t.isBetween(e[0],e[1],"[]"):e.isSame(t,"day")}).length&&e.classList.add(a.isHighlighted),e.tabIndex=e.classList.contains("is-locked")?-1:0,this.emit("render:day",e,t),e},e.prototype.renderFooter=function(){var t=document.createElement("div");if(t.className=a.containerFooter,this.options.footerHTML?t.innerHTML=this.options.footerHTML:t.innerHTML='\n \n \n \n ",this.options.singleMode){if(1===this.datePicked.length){var e=this.datePicked[0].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=e}}else if(1===this.datePicked.length&&t.querySelector("."+a.buttonApply).setAttribute("disabled",""),2===this.datePicked.length){e=this.datePicked[0].format(this.options.format,this.options.lang);var n=this.datePicked[1].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=""+e+this.options.delimiter+n}return this.emit("render:footer",t),t},e.prototype.renderWeekNumber=function(t){var e=document.createElement("div"),n=t.getWeek(this.options.firstDay);return e.className=a.weekNumber,e.innerHTML=53===n&&0===t.getMonth()?"53 / 1":n,e},e.prototype.renderTooltip=function(){var t=document.createElement("div");return t.className=a.containerTooltip,t},e.prototype.weekdayName=function(t,e){return void 0===e&&(e="short"),new Date(1970,0,t,12,0,0,0).toLocaleString(this.options.lang,{weekday:e})},e.prototype.calcSkipDays=function(t){var e=t.getDay()-this.options.firstDay;return e<0&&(e+=7),e},e}(o.LPCore);e.Calendar=c},function(t,e,n){"use strict";var i,r=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),o=this&&this.__assign||function(){return(o=Object.assign||function(t){for(var e,n=1,i=arguments.length;n',nextMonth:'',reset:'\n \n \n '},tooltipText:{one:"day",other:"days"}},n.options=o(o({},n.options),e.element.dataset),Object.keys(n.options).forEach(function(t){"true"!==n.options[t]&&"false"!==n.options[t]||(n.options[t]="true"===n.options[t])});var i=o(o({},n.options.dropdowns),e.dropdowns),r=o(o({},n.options.buttonText),e.buttonText),s=o(o({},n.options.tooltipText),e.tooltipText);n.options=o(o({},n.options),e),n.options.dropdowns=o({},i),n.options.buttonText=o({},r),n.options.tooltipText=o({},s),n.options.elementEnd||(n.options.allowRepick=!1),n.options.lockDays.length&&(n.options.lockDays=a.DateTime.convertArray(n.options.lockDays,n.options.lockDaysFormat)),n.options.highlightedDays.length&&(n.options.highlightedDays=a.DateTime.convertArray(n.options.highlightedDays,n.options.highlightedDaysFormat));var l=n.parseInput(),c=l[0],u=l[1];n.options.startDate&&(n.options.singleMode||n.options.endDate)&&(c=new a.DateTime(n.options.startDate,n.options.format,n.options.lang)),c&&n.options.endDate&&(u=new a.DateTime(n.options.endDate,n.options.format,n.options.lang)),c instanceof a.DateTime&&!isNaN(c.getTime())&&(n.options.startDate=c),n.options.startDate&&u instanceof a.DateTime&&!isNaN(u.getTime())&&(n.options.endDate=u),!n.options.singleMode||n.options.startDate instanceof a.DateTime||(n.options.startDate=null),n.options.singleMode||n.options.startDate instanceof a.DateTime&&n.options.endDate instanceof a.DateTime||(n.options.startDate=null,n.options.endDate=null);for(var d=0;dwindow.innerHeight,c=e.top+o-n.height>=n.height;l&&c&&(s=e.top+o-n.height)}if(/left|right/.test(i[0])||i[1]&&"auto"!==i[1]&&/left|right/.test(i[1]))a=/left|right/.test(i[0])?e[i[0]]+r:e[i[1]]+r,"right"!==i[0]&&"right"!==i[1]||(a-=n.width);else{a=e.left+r,l=e.left+n.width>window.innerWidth;var u=e.right+r-n.width>=0;l&&u&&(a=e.right+r-n.width)}return{left:a,top:s}},e}(s.EventEmitter);e.LPCore=c},function(t,e,n){"use strict";var i,r="object"==typeof Reflect?Reflect:null,o=r&&"function"==typeof r.apply?r.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};i=r&&"function"==typeof r.ownKeys?r.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var l=10;function c(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function u(t,e,n,i){var r,o,s,a;if("function"!=typeof n)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof n);if(void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),o=t._events),s=o[e]),void 0===s)s=o[e]=n,++t._eventsCount;else if("function"==typeof s?s=o[e]=i?[n,s]:[s,n]:i?s.unshift(n):s.push(n),(r=c(t))>0&&s.length>r&&!s.warned){s.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=t,l.type=e,l.count=s.length,a=l,console&&console.warn&&console.warn(a)}return t}function d(){for(var t=[],e=0;e0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var l=r[t];if(void 0===l)return!1;if("function"==typeof l)o(l,this,e);else{var c=l.length,u=f(l,c);for(n=0;n=0;o--)if(n[o]===e||n[o].listener===e){s=n[o].listener,r=o;break}if(r<0)return this;0===r?n.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},a.prototype.listeners=function(t){return p(this,t,!0)},a.prototype.rawListeners=function(t){return p(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):m.call(t,e)},a.prototype.listenerCount=m,a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(t,e,n){(e=n(9)(!1)).push([t.i,':root{--litepicker-container-months-color-bg: #fff;--litepicker-container-months-box-shadow-color: #ddd;--litepicker-footer-color-bg: #fafafa;--litepicker-footer-box-shadow-color: #ddd;--litepicker-tooltip-color-bg: #fff;--litepicker-month-header-color: #333;--litepicker-button-prev-month-color: #9e9e9e;--litepicker-button-next-month-color: #9e9e9e;--litepicker-button-prev-month-color-hover: #2196f3;--litepicker-button-next-month-color-hover: #2196f3;--litepicker-month-width: calc(var(--litepicker-day-width) * 7);--litepicker-month-weekday-color: #9e9e9e;--litepicker-month-week-number-color: #9e9e9e;--litepicker-day-width: 38px;--litepicker-day-color: #333;--litepicker-day-color-hover: #2196f3;--litepicker-is-today-color: #f44336;--litepicker-is-in-range-color: #bbdefb;--litepicker-is-locked-color: #9e9e9e;--litepicker-is-start-color: #fff;--litepicker-is-start-color-bg: #2196f3;--litepicker-is-end-color: #fff;--litepicker-is-end-color-bg: #2196f3;--litepicker-button-cancel-color: #fff;--litepicker-button-cancel-color-bg: #9e9e9e;--litepicker-button-apply-color: #fff;--litepicker-button-apply-color-bg: #2196f3;--litepicker-button-reset-color: #909090;--litepicker-button-reset-color-hover: #2196f3;--litepicker-highlighted-day-color: #333;--litepicker-highlighted-day-color-bg: #ffeb3b}.show-week-numbers{--litepicker-month-width: calc(var(--litepicker-day-width) * 8)}.litepicker{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-size:0.8em;display:none}.litepicker button{border:none;background:none}.litepicker .container__main{display:-webkit-box;display:-ms-flexbox;display:flex}.litepicker .container__months{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background-color:var(--litepicker-container-months-color-bg);border-radius:5px;-webkit-box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);width:calc(var(--litepicker-month-width) + 10px);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months.columns-2{width:calc((var(--litepicker-month-width) * 2) + 20px)}.litepicker .container__months.columns-3{width:calc((var(--litepicker-month-width) * 3) + 30px)}.litepicker .container__months.columns-4{width:calc((var(--litepicker-month-width) * 4) + 40px)}.litepicker .container__months.split-view .month-item-header .button-previous-month,.litepicker .container__months.split-view .month-item-header .button-next-month{visibility:visible}.litepicker .container__months .month-item{padding:5px;width:var(--litepicker-month-width);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months .month-item-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-weight:500;padding:10px 5px;text-align:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--litepicker-month-header-color)}.litepicker .container__months .month-item-header div{-webkit-box-flex:1;-ms-flex:1;flex:1}.litepicker .container__months .month-item-header div>.month-item-name{margin-right:5px}.litepicker .container__months .month-item-header div>.month-item-year{padding:0}.litepicker .container__months .month-item-header .reset-button{color:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button>svg{fill:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button *{pointer-events:none}.litepicker .container__months .month-item-header .reset-button:hover{color:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .reset-button:hover>svg{fill:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .button-previous-month,.litepicker .container__months .month-item-header .button-next-month{visibility:hidden;text-decoration:none;padding:3px 5px;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__months .month-item-header .button-previous-month *,.litepicker .container__months .month-item-header .button-next-month *{pointer-events:none}.litepicker .container__months .month-item-header .button-previous-month{color:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month>svg,.litepicker .container__months .month-item-header .button-previous-month>img{fill:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month:hover{color:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-previous-month:hover>svg{fill:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month{color:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month>svg,.litepicker .container__months .month-item-header .button-next-month>img{fill:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month:hover{color:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month:hover>svg{fill:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-weekdays-row{display:-webkit-box;display:-ms-flexbox;display:flex;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;color:var(--litepicker-month-weekday-color)}.litepicker .container__months .month-item-weekdays-row>div{padding:5px 0;font-size:85%;-webkit-box-flex:1;-ms-flex:1;flex:1;width:var(--litepicker-day-width);text-align:center}.litepicker .container__months .month-item:first-child .button-previous-month{visibility:visible}.litepicker .container__months .month-item:last-child .button-next-month{visibility:visible}.litepicker .container__months .month-item.no-previous-month .button-previous-month{visibility:hidden}.litepicker .container__months .month-item.no-next-month .button-next-month{visibility:hidden}.litepicker .container__days{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;text-align:center;-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__days>div,.litepicker .container__days>a{padding:5px 0;width:var(--litepicker-day-width)}.litepicker .container__days .day-item{color:var(--litepicker-day-color);text-align:center;text-decoration:none;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__days .day-item:hover{color:var(--litepicker-day-color-hover);-webkit-box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover);box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover)}.litepicker .container__days .day-item.is-today{color:var(--litepicker-is-today-color)}.litepicker .container__days .day-item.is-locked{color:var(--litepicker-is-locked-color)}.litepicker .container__days .day-item.is-locked:hover{color:var(--litepicker-is-locked-color);-webkit-box-shadow:none;box-shadow:none;cursor:default}.litepicker .container__days .day-item.is-in-range{background-color:var(--litepicker-is-in-range-color);border-radius:0}.litepicker .container__days .day-item.is-start-date{color:var(--litepicker-is-start-color);background-color:var(--litepicker-is-start-color-bg);border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-flipped{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date{color:var(--litepicker-is-end-color);background-color:var(--litepicker-is-end-color-bg);border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date.is-flipped{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-end-date{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-highlighted{color:var(--litepicker-highlighted-day-color);background-color:var(--litepicker-highlighted-day-color-bg)}.litepicker .container__days .week-number{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:var(--litepicker-month-week-number-color);font-size:85%}.litepicker .container__footer{text-align:right;padding:10px 5px;margin:0 5px;background-color:var(--litepicker-footer-color-bg);-webkit-box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);border-bottom-left-radius:5px;border-bottom-right-radius:5px}.litepicker .container__footer .preview-date-range{margin-right:10px;font-size:90%}.litepicker .container__footer .button-cancel{background-color:var(--litepicker-button-cancel-color-bg);color:var(--litepicker-button-cancel-color);border:0;padding:3px 7px 4px;border-radius:3px}.litepicker .container__footer .button-cancel *{pointer-events:none}.litepicker .container__footer .button-apply{background-color:var(--litepicker-button-apply-color-bg);color:var(--litepicker-button-apply-color);border:0;padding:3px 7px 4px;border-radius:3px;margin-left:10px;margin-right:10px}.litepicker .container__footer .button-apply:disabled{opacity:0.7}.litepicker .container__footer .button-apply *{pointer-events:none}.litepicker .container__tooltip{position:absolute;margin-top:-4px;padding:4px 8px;border-radius:4px;background-color:var(--litepicker-tooltip-color-bg);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25);white-space:nowrap;font-size:11px;pointer-events:none;visibility:hidden}.litepicker .container__tooltip:before{position:absolute;bottom:-5px;left:calc(50% - 5px);border-top:5px solid rgba(0,0,0,0.12);border-right:5px solid transparent;border-left:5px solid transparent;content:""}.litepicker .container__tooltip:after{position:absolute;bottom:-4px;left:calc(50% - 4px);border-top:4px solid var(--litepicker-tooltip-color-bg);border-right:4px solid transparent;border-left:4px solid transparent;content:""}\n',""]),e.locals={showWeekNumbers:"show-week-numbers",litepicker:"litepicker",containerMain:"container__main",containerMonths:"container__months",columns2:"columns-2",columns3:"columns-3",columns4:"columns-4",splitView:"split-view",monthItemHeader:"month-item-header",buttonPreviousMonth:"button-previous-month",buttonNextMonth:"button-next-month",monthItem:"month-item",monthItemName:"month-item-name",monthItemYear:"month-item-year",resetButton:"reset-button",monthItemWeekdaysRow:"month-item-weekdays-row",noPreviousMonth:"no-previous-month",noNextMonth:"no-next-month",containerDays:"container__days",dayItem:"day-item",isToday:"is-today",isLocked:"is-locked",isInRange:"is-in-range",isStartDate:"is-start-date",isFlipped:"is-flipped",isEndDate:"is-end-date",isHighlighted:"is-highlighted",weekNumber:"week-number",containerFooter:"container__footer",previewDateRange:"preview-date-range",buttonCancel:"button-cancel",buttonApply:"button-apply",containerTooltip:"container__tooltip"},t.exports=e},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=function(t,e){var n,i,r,o=t[1]||"",s=t[3];if(!s)return o;if(e&&"function"==typeof btoa){var a=(n=s,i=btoa(unescape(encodeURIComponent(JSON.stringify(n)))),r="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(i),"/*# ".concat(r," */")),l=s.sources.map(function(t){return"/*# sourceURL=".concat(s.sourceRoot||"").concat(t," */")});return[o].concat(l).concat([a]).join("\n")}return[o].join("\n")}(e,t);return e[2]?"@media ".concat(e[2]," {").concat(n,"}"):n}).join("")},e.i=function(t,n,i){"string"==typeof t&&(t=[[null,t,""]]);var r={};if(i)for(var o=0;othis.options.endDate.getTime()&&(this.options.endDate=this.options.startDate.clone(),this.options.startDate=new r.DateTime(t,this.options.format,this.options.lang)),this.updateInput())},o.Litepicker.prototype.setDateRange=function(t,e,n){void 0===n&&(n=!1),this.triggerElement=void 0;var i=new r.DateTime(t,this.options.format,this.options.lang),o=new r.DateTime(e,this.options.format,this.options.lang);(this.options.disallowLockDaysInRange?s.rangeIsLocked([i,o],this.options):s.dateIsLocked(i,this.options,[i,o])||s.dateIsLocked(o,this.options,[i,o]))&&!n?this.emit("error:range",[i,o]):(this.setStartDate(i),this.setEndDate(o),this.options.inlineMode&&this.render(),this.updateInput(),this.emit("selected",this.getStartDate(),this.getEndDate()))},o.Litepicker.prototype.gotoDate=function(t,e){void 0===e&&(e=0);var n=new r.DateTime(t);n.setDate(1),this.calendars[e]=n.clone(),this.render()},o.Litepicker.prototype.setLockDays=function(t){this.options.lockDays=r.DateTime.convertArray(t,this.options.lockDaysFormat),this.render()},o.Litepicker.prototype.setHighlightedDays=function(t){this.options.highlightedDays=r.DateTime.convertArray(t,this.options.highlightedDaysFormat),this.render()},o.Litepicker.prototype.setOptions=function(t){delete t.element,delete t.elementEnd,delete t.parentEl,t.startDate&&(t.startDate=new r.DateTime(t.startDate,this.options.format,this.options.lang)),t.endDate&&(t.endDate=new r.DateTime(t.endDate,this.options.format,this.options.lang));var e=i(i({},this.options.dropdowns),t.dropdowns),n=i(i({},this.options.buttonText),t.buttonText),o=i(i({},this.options.tooltipText),t.tooltipText);this.options=i(i({},this.options),t),this.options.dropdowns=i({},e),this.options.buttonText=i({},n),this.options.tooltipText=i({},o),!this.options.singleMode||this.options.startDate instanceof r.DateTime||(this.options.startDate=null,this.options.endDate=null),this.options.singleMode||this.options.startDate instanceof r.DateTime&&this.options.endDate instanceof r.DateTime||(this.options.startDate=null,this.options.endDate=null);for(var s=0;sMath.abs(o),a=t.options.numberOfMonths,l=null,c=!1,u="",d=Array.from(t.ui.querySelectorAll(".month-item"));if(s){var h=t.DateTime(t.ui.querySelector(".day-item").dataset.time),p=Number("".concat(1-Math.abs(r)/100)),m=0;if(r>0){m=-Math.abs(r),l=h.clone().add(a,"month");var f=t.options.maxDate;c=!f||l.isSameOrBefore(t.DateTime(f),"month"),u="next"}else{m=Math.abs(r),l=h.clone().subtract(a,"month");var g=t.options.minDate;c=!g||l.isSameOrAfter(t.DateTime(g),"month"),u="prev"}c&&d.map(function(t){t.style.opacity=p,t.style.transform="translateX(".concat(m,"px)")})}Math.abs(r)+Math.abs(o)>100&&s&&l&&c&&(t.touchTargetMonth=u,t.gotoDate(l))}},!!n&&{passive:!0}),t.ui.addEventListener("touchend",function(e){t.touchTargetMonth||Array.from(t.ui.querySelectorAll(".month-item")).map(function(t){t.style.transform="translateX(0px)",t.style.opacity=1}),t.xTouchDown=null,t.yTouchDown=null},!!n&&{passive:!0})}})},function(t,e,n){var i=n(7);"string"==typeof i&&(i=[[t.i,i,""]]);var r={insert:function(t){var e=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;window.disableLitepickerStyles||(n?n.nextSibling?e.insertBefore(t,n.nextSibling):e.appendChild(t):e.insertBefore(t,e.firstChild),window._lastElementInsertedByStyleLoader=t)},singleton:!1};n(1)(i,r),i.locals&&(t.exports=i.locals)},function(t,e,n){(e=n(0)(!1)).push([t.i,':root {\n --litepicker-mobilefriendly-backdrop-color-bg: #000;\n}\n\n.litepicker-backdrop {\n display: none;\n background-color: var(--litepicker-mobilefriendly-backdrop-color-bg);\n opacity: 0.3;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n.litepicker-open {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] {\n transform: translate(-50%, -50%);\n font-size: 1.1rem;\n --litepicker-container-months-box-shadow-color: #616161;\n}\n.litepicker.mobilefriendly-portrait {\n --litepicker-day-width: 13.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n.litepicker.mobilefriendly-landscape {\n --litepicker-day-width: 5.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__months .month-item-header {\n height: var(--litepicker-day-width);\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__days > div {\n height: var(--litepicker-day-width);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item {\n transform-origin: center;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-next {\n animation-name: lp-bounce-target-next;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-prev {\n animation-name: lp-bounce-target-prev;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n@keyframes lp-bounce-target-next {\n from {\n transform: translateX(100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}\n\n@keyframes lp-bounce-target-prev {\n from {\n transform: translateX(-100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}',""]),t.exports=e}])},3829:function(t,e,n){"use strict";n.r(e)},2481:function(t,e,n){"use strict";var i=n(8252),r=n(1958),o=TypeError;t.exports=function(t){if(i(t))return t;throw new o(r(t)+" is not a function")}},7938:function(t,e,n){"use strict";var i=n(2666),r=n(3369),o=n(1250).f,s=i("unscopables"),a=Array.prototype;void 0===a[s]&&o(a,s,{configurable:!0,value:r(null)}),t.exports=function(t){a[s][t]=!0}},3162:function(t,e,n){"use strict";var i=n(8271),r=String,o=TypeError;t.exports=function(t){if(i(t))return t;throw new o(r(t)+" is not an object")}},8658:function(t,e,n){"use strict";var i=n(2364),r=n(9283),o=n(6013),s=function(t){return function(e,n,s){var a=i(e),l=o(a);if(0===l)return!t&&-1;var c,u=r(s,l);if(t&&n!=n){for(;l>u;)if((c=a[u++])!=c)return!0}else for(;l>u;u++)if((t||u in a)&&a[u]===n)return t||u||0;return!t&&-1}};t.exports={includes:s(!0),indexOf:s(!1)}},7409:function(t,e,n){"use strict";var i=n(2289),r=i({}.toString),o=i("".slice);t.exports=function(t){return o(r(t),8,-1)}},4993:function(t,e,n){"use strict";var i=n(9522),r=n(5456),o=n(6056),s=n(1250);t.exports=function(t,e,n){for(var a=r(e),l=s.f,c=o.f,u=0;u0&&i[0]<4?1:+(i[0]+i[1])),!r&&s&&(!(i=s.match(/Edge\/(\d+)/))||i[1]>=74)&&(i=s.match(/Chrome\/(\d+)/))&&(r=+i[1]),t.exports=r},7725:function(t,e,n){"use strict";var i=n(3405),r=n(6056).f,o=n(232),s=n(3589),a=n(7214),l=n(4993),c=n(5129);t.exports=function(t,e){var n,u,d,h,p,m=t.target,f=t.global,g=t.stat;if(n=f?i:g?i[m]||a(m,{}):i[m]&&i[m].prototype)for(u in e){if(h=e[u],d=t.dontCallGetSet?(p=r(n,u))&&p.value:n[u],!c(f?u:m+(g?".":"#")+u,t.forced)&&void 0!==d){if(typeof h==typeof d)continue;l(h,d)}(t.sham||d&&d.sham)&&o(h,"sham",!0),s(n,u,h,t)}}},8930:function(t){"use strict";t.exports=function(t){try{return!!t()}catch(t){return!0}}},5647:function(t,e,n){"use strict";var i=n(8930);t.exports=!i(function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")})},3176:function(t,e,n){"use strict";var i=n(5647),r=Function.prototype.call;t.exports=i?r.bind(r):function(){return r.apply(r,arguments)}},3743:function(t,e,n){"use strict";var i=n(7101),r=n(9522),o=Function.prototype,s=i&&Object.getOwnPropertyDescriptor,a=r(o,"name"),l=a&&"something"===function(){}.name,c=a&&(!i||i&&s(o,"name").configurable);t.exports={EXISTS:a,PROPER:l,CONFIGURABLE:c}},2289:function(t,e,n){"use strict";var i=n(5647),r=Function.prototype,o=r.call,s=i&&r.bind.bind(o,o);t.exports=i?s:function(t){return function(){return o.apply(t,arguments)}}},3220:function(t,e,n){"use strict";var i=n(3405),r=n(8252);t.exports=function(t,e){return arguments.length<2?(n=i[t],r(n)?n:void 0):i[t]&&i[t][e];var n}},3377:function(t,e,n){"use strict";var i=n(2481),r=n(3022);t.exports=function(t,e){var n=t[e];return r(n)?void 0:i(n)}},3405:function(t,e,n){"use strict";var i=function(t){return t&&t.Math===Math&&t};t.exports=i("object"==typeof globalThis&&globalThis)||i("object"==typeof window&&window)||i("object"==typeof self&&self)||i("object"==typeof n.g&&n.g)||i("object"==typeof this&&this)||function(){return this}()||Function("return this")()},9522:function(t,e,n){"use strict";var i=n(2289),r=n(1724),o=i({}.hasOwnProperty);t.exports=Object.hasOwn||function(t,e){return o(r(t),e)}},4036:function(t){"use strict";t.exports={}},9810:function(t,e,n){"use strict";var i=n(3220);t.exports=i("document","documentElement")},1782:function(t,e,n){"use strict";var i=n(7101),r=n(8930),o=n(2998);t.exports=!i&&!r(function(){return 7!==Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a})},1792:function(t,e,n){"use strict";var i=n(2289),r=n(8930),o=n(7409),s=Object,a=i("".split);t.exports=r(function(){return!s("z").propertyIsEnumerable(0)})?function(t){return"String"===o(t)?a(t,""):s(t)}:s},4117:function(t,e,n){"use strict";var i=n(2289),r=n(8252),o=n(8486),s=i(Function.toString);r(o.inspectSource)||(o.inspectSource=function(t){return s(t)}),t.exports=o.inspectSource},4206:function(t,e,n){"use strict";var i,r,o,s=n(3337),a=n(3405),l=n(8271),c=n(232),u=n(9522),d=n(8486),h=n(4040),p=n(4036),m="Object already initialized",f=a.TypeError,g=a.WeakMap;if(s||d.state){var v=d.state||(d.state=new g);v.get=v.get,v.has=v.has,v.set=v.set,i=function(t,e){if(v.has(t))throw new f(m);return e.facade=t,v.set(t,e),e},r=function(t){return v.get(t)||{}},o=function(t){return v.has(t)}}else{var y=h("state");p[y]=!0,i=function(t,e){if(u(t,y))throw new f(m);return e.facade=t,c(t,y,e),e},r=function(t){return u(t,y)?t[y]:{}},o=function(t){return u(t,y)}}t.exports={set:i,get:r,has:o,enforce:function(t){return o(t)?r(t):i(t,{})},getterFor:function(t){return function(e){var n;if(!l(e)||(n=r(e)).type!==t)throw new f("Incompatible receiver, "+t+" required");return n}}}},8252:function(t){"use strict";var e="object"==typeof document&&document.all;t.exports=void 0===e&&void 0!==e?function(t){return"function"==typeof t||t===e}:function(t){return"function"==typeof t}},5129:function(t,e,n){"use strict";var i=n(8930),r=n(8252),o=/#|\.prototype\./,s=function(t,e){var n=l[a(t)];return n===u||n!==c&&(r(e)?i(e):!!e)},a=s.normalize=function(t){return String(t).replace(o,".").toLowerCase()},l=s.data={},c=s.NATIVE="N",u=s.POLYFILL="P";t.exports=s},3022:function(t){"use strict";t.exports=function(t){return null==t}},8271:function(t,e,n){"use strict";var i=n(8252);t.exports=function(t){return"object"==typeof t?null!==t:i(t)}},4214:function(t){"use strict";t.exports=!1},8944:function(t,e,n){"use strict";var i=n(3220),r=n(8252),o=n(8130),s=n(5537),a=Object;t.exports=s?function(t){return"symbol"==typeof t}:function(t){var e=i("Symbol");return r(e)&&o(e.prototype,a(t))}},6013:function(t,e,n){"use strict";var i=n(5531);t.exports=function(t){return i(t.length)}},4034:function(t,e,n){"use strict";var i=n(2289),r=n(8930),o=n(8252),s=n(9522),a=n(7101),l=n(3743).CONFIGURABLE,c=n(4117),u=n(4206),d=u.enforce,h=u.get,p=String,m=Object.defineProperty,f=i("".slice),g=i("".replace),v=i([].join),y=a&&!r(function(){return 8!==m(function(){},"length",{value:8}).length}),b=String(String).split("String"),_=t.exports=function(t,e,n){"Symbol("===f(p(e),0,7)&&(e="["+g(p(e),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),n&&n.getter&&(e="get "+e),n&&n.setter&&(e="set "+e),(!s(t,"name")||l&&t.name!==e)&&(a?m(t,"name",{value:e,configurable:!0}):t.name=e),y&&n&&s(n,"arity")&&t.length!==n.arity&&m(t,"length",{value:n.arity});try{n&&s(n,"constructor")&&n.constructor?a&&m(t,"prototype",{writable:!1}):t.prototype&&(t.prototype=void 0)}catch(t){}var i=d(t);return s(i,"source")||(i.source=v(b,"string"==typeof e?e:"")),t};Function.prototype.toString=_(function(){return o(this)&&h(this).source||c(this)},"toString")},7966:function(t){"use strict";var e=Math.ceil,n=Math.floor;t.exports=Math.trunc||function(t){var i=+t;return(i>0?n:e)(i)}},3369:function(t,e,n){"use strict";var i,r=n(3162),o=n(5422),s=n(7658),a=n(4036),l=n(9810),c=n(2998),u=n(4040),d="prototype",h="script",p=u("IE_PROTO"),m=function(){},f=function(t){return"<"+h+">"+t+""},g=function(t){t.write(f("")),t.close();var e=t.parentWindow.Object;return t=null,e},v=function(){try{i=new ActiveXObject("htmlfile")}catch(t){}var t,e,n;v="undefined"!=typeof document?document.domain&&i?g(i):(e=c("iframe"),n="java"+h+":",e.style.display="none",l.appendChild(e),e.src=String(n),(t=e.contentWindow.document).open(),t.write(f("document.F=Object")),t.close(),t.F):g(i);for(var r=s.length;r--;)delete v[d][s[r]];return v()};a[p]=!0,t.exports=Object.create||function(t,e){var n;return null!==t?(m[d]=r(t),n=new m,m[d]=null,n[p]=t):n=v(),void 0===e?n:o.f(n,e)}},5422:function(t,e,n){"use strict";var i=n(7101),r=n(3667),o=n(1250),s=n(3162),a=n(2364),l=n(7185);e.f=i&&!r?Object.defineProperties:function(t,e){s(t);for(var n,i=a(e),r=l(e),c=r.length,u=0;c>u;)o.f(t,n=r[u++],i[n]);return t}},1250:function(t,e,n){"use strict";var i=n(7101),r=n(1782),o=n(3667),s=n(3162),a=n(3704),l=TypeError,c=Object.defineProperty,u=Object.getOwnPropertyDescriptor,d="enumerable",h="configurable",p="writable";e.f=i?o?function(t,e,n){if(s(t),e=a(e),s(n),"function"==typeof t&&"prototype"===e&&"value"in n&&p in n&&!n[p]){var i=u(t,e);i&&i[p]&&(t[e]=n.value,n={configurable:h in n?n[h]:i[h],enumerable:d in n?n[d]:i[d],writable:!1})}return c(t,e,n)}:c:function(t,e,n){if(s(t),e=a(e),s(n),r)try{return c(t,e,n)}catch(t){}if("get"in n||"set"in n)throw new l("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},6056:function(t,e,n){"use strict";var i=n(7101),r=n(3176),o=n(6640),s=n(9299),a=n(2364),l=n(3704),c=n(9522),u=n(1782),d=Object.getOwnPropertyDescriptor;e.f=i?d:function(t,e){if(t=a(t),e=l(e),u)try{return d(t,e)}catch(t){}if(c(t,e))return s(!r(o.f,t,e),t[e])}},7469:function(t,e,n){"use strict";var i=n(6067),r=n(7658).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return i(t,r)}},4540:function(t,e){"use strict";e.f=Object.getOwnPropertySymbols},8130:function(t,e,n){"use strict";var i=n(2289);t.exports=i({}.isPrototypeOf)},6067:function(t,e,n){"use strict";var i=n(2289),r=n(9522),o=n(2364),s=n(8658).indexOf,a=n(4036),l=i([].push);t.exports=function(t,e){var n,i=o(t),c=0,u=[];for(n in i)!r(a,n)&&r(i,n)&&l(u,n);for(;e.length>c;)r(i,n=e[c++])&&(~s(u,n)||l(u,n));return u}},7185:function(t,e,n){"use strict";var i=n(6067),r=n(7658);t.exports=Object.keys||function(t){return i(t,r)}},6640:function(t,e){"use strict";var n={}.propertyIsEnumerable,i=Object.getOwnPropertyDescriptor,r=i&&!n.call({1:2},1);e.f=r?function(t){var e=i(this,t);return!!e&&e.enumerable}:n},5519:function(t,e,n){"use strict";var i=n(3176),r=n(8252),o=n(8271),s=TypeError;t.exports=function(t,e){var n,a;if("string"===e&&r(n=t.toString)&&!o(a=i(n,t)))return a;if(r(n=t.valueOf)&&!o(a=i(n,t)))return a;if("string"!==e&&r(n=t.toString)&&!o(a=i(n,t)))return a;throw new s("Can't convert object to primitive value")}},5456:function(t,e,n){"use strict";var i=n(3220),r=n(2289),o=n(7469),s=n(4540),a=n(3162),l=r([].concat);t.exports=i("Reflect","ownKeys")||function(t){var e=o.f(a(t)),n=s.f;return n?l(e,n(t)):e}},2341:function(t,e,n){"use strict";var i=n(3022),r=TypeError;t.exports=function(t){if(i(t))throw new r("Can't call method on "+t);return t}},4040:function(t,e,n){"use strict";var i=n(8762),r=n(2161),o=i("keys");t.exports=function(t){return o[t]||(o[t]=r(t))}},8486:function(t,e,n){"use strict";var i=n(4214),r=n(3405),o=n(7214),s="__core-js_shared__",a=t.exports=r[s]||o(s,{});(a.versions||(a.versions=[])).push({version:"3.49.0",mode:i?"pure":"global",copyright:"© 2013–2025 Denis Pushkarev (zloirock.ru), 2025–2026 CoreJS Company (core-js.io). All rights reserved.",license:"https://github.com/zloirock/core-js/blob/v3.49.0/LICENSE",source:"https://github.com/zloirock/core-js"})},8762:function(t,e,n){"use strict";var i=n(8486);t.exports=function(t,e){return i[t]||(i[t]=e||{})}},1520:function(t,e,n){"use strict";var i=n(5168),r=n(8930),o=n(3405).String;t.exports=!!Object.getOwnPropertySymbols&&!r(function(){var t=Symbol("symbol detection");return!o(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&i&&i<41})},9283:function(t,e,n){"use strict";var i=n(136),r=Math.max,o=Math.min;t.exports=function(t,e){var n=i(t);return n<0?r(n+e,0):o(n,e)}},2364:function(t,e,n){"use strict";var i=n(1792),r=n(2341);t.exports=function(t){return i(r(t))}},136:function(t,e,n){"use strict";var i=n(7966);t.exports=function(t){var e=+t;return e!=e||0===e?0:i(e)}},5531:function(t,e,n){"use strict";var i=n(136),r=Math.min;t.exports=function(t){var e=i(t);return e>0?r(e,9007199254740991):0}},1724:function(t,e,n){"use strict";var i=n(2341),r=Object;t.exports=function(t){return r(i(t))}},4610:function(t,e,n){"use strict";var i=n(3176),r=n(8271),o=n(8944),s=n(3377),a=n(5519),l=n(2666),c=TypeError,u=l("toPrimitive");t.exports=function(t,e){if(!r(t)||o(t))return t;var n,l=s(t,u);if(l){if(void 0===e&&(e="default"),n=i(l,t,e),!r(n)||o(n))return n;throw new c("Can't convert object to primitive value")}return void 0===e&&(e="number"),a(t,e)}},3704:function(t,e,n){"use strict";var i=n(4610),r=n(8944);t.exports=function(t){var e=i(t,"string");return r(e)?e:e+""}},1958:function(t){"use strict";var e=String;t.exports=function(t){try{return e(t)}catch(t){return"Object"}}},2161:function(t,e,n){"use strict";var i=n(2289),r=0,o=Math.random(),s=i(1.1.toString);t.exports=function(t){return"Symbol("+(void 0===t?"":t)+")_"+s(++r+o,36)}},5537:function(t,e,n){"use strict";var i=n(1520);t.exports=i&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},3667:function(t,e,n){"use strict";var i=n(7101),r=n(8930);t.exports=i&&r(function(){return 42!==Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype})},3337:function(t,e,n){"use strict";var i=n(3405),r=n(8252),o=i.WeakMap;t.exports=r(o)&&/native code/.test(String(o))},2666:function(t,e,n){"use strict";var i=n(3405),r=n(8762),o=n(9522),s=n(2161),a=n(1520),l=n(5537),c=i.Symbol,u=r("wks"),d=l?c.for||c:c&&c.withoutSetter||s;t.exports=function(t){return o(u,t)||(u[t]=a&&o(c,t)?c[t]:d("Symbol."+t)),u[t]}},9690:function(t,e,n){"use strict";var i=n(7725),r=n(8658).includes,o=n(8930),s=n(7938),a=o(function(){return!Array(1).includes()}),l=o(function(){return[,1].includes(void 0,1)});i({target:"Array",proto:!0,forced:a||l},{includes:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),s("includes")},2647:function(t,e,n){"use strict";n.d(e,{c9:function(){return bi},dw:function(){return xn},wB:function(){return wt}});class i extends Error{}class r extends i{constructor(t){super(`Invalid DateTime: ${t.toMessage()}`)}}class o extends i{constructor(t){super(`Invalid Interval: ${t.toMessage()}`)}}class s extends i{constructor(t){super(`Invalid Duration: ${t.toMessage()}`)}}class a extends i{}class l extends i{constructor(t){super(`Invalid unit ${t}`)}}class c extends i{}class u extends i{constructor(){super("Zone is an abstract class")}}const d="numeric",h="short",p="long",m={year:d,month:d,day:d},f={year:d,month:h,day:d},g={year:d,month:h,day:d,weekday:h},v={year:d,month:p,day:d},y={year:d,month:p,day:d,weekday:p},b={hour:d,minute:d},_={hour:d,minute:d,second:d},w={hour:d,minute:d,second:d,timeZoneName:h},k={hour:d,minute:d,second:d,timeZoneName:p},T={hour:d,minute:d,hourCycle:"h23"},E={hour:d,minute:d,second:d,hourCycle:"h23"},S={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:h},x={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:p},D={year:d,month:d,day:d,hour:d,minute:d},O={year:d,month:d,day:d,hour:d,minute:d,second:d},L={year:d,month:h,day:d,hour:d,minute:d},C={year:d,month:h,day:d,hour:d,minute:d,second:d},A={year:d,month:h,day:d,weekday:h,hour:d,minute:d},M={year:d,month:p,day:d,hour:d,minute:d,timeZoneName:h},I={year:d,month:p,day:d,hour:d,minute:d,second:d,timeZoneName:h},N={year:d,month:p,day:d,weekday:p,hour:d,minute:d,timeZoneName:p},P={year:d,month:p,day:d,weekday:p,hour:d,minute:d,second:d,timeZoneName:p};class F{get type(){throw new u}get name(){throw new u}get ianaName(){return this.name}get isUniversal(){throw new u}offsetName(t,e){throw new u}formatOffset(t,e){throw new u}offset(t){throw new u}equals(t){throw new u}get isValid(){throw new u}}let j=null;class R extends F{static get instance(){return null===j&&(j=new R),j}get type(){return"system"}get name(){return(new Intl.DateTimeFormat).resolvedOptions().timeZone}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return re(t,e,n)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){return-new Date(t).getTimezoneOffset()}equals(t){return"system"===t.type}get isValid(){return!0}}const $=new Map;const q={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6};const H=new Map;class V extends F{static create(t){let e=H.get(t);return void 0===e&&H.set(t,e=new V(t)),e}static resetCache(){H.clear(),$.clear()}static isValidSpecifier(t){return this.isValidZone(t)}static isValidZone(t){if(!t)return!1;try{return new Intl.DateTimeFormat("en-US",{timeZone:t}).format(),!0}catch(t){return!1}}constructor(t){super(),this.zoneName=t,this.valid=V.isValidZone(t)}get type(){return"iana"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return re(t,e,n,this.name)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){if(!this.valid)return NaN;const e=new Date(t);if(isNaN(e))return NaN;const n=function(t){let e=$.get(t);return void 0===e&&(e=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short"}),$.set(t,e)),e}(this.name);let[i,r,o,s,a,l,c]=n.formatToParts?function(t,e){const n=t.formatToParts(e),i=[];for(let t=0;t=0?d:1e3+d,(te({year:i,month:r,day:o,hour:24===a?0:a,minute:l,second:c,millisecond:0})-u)/6e4}equals(t){return"iana"===t.type&&t.name===this.name}get isValid(){return this.valid}}let z={};const B=new Map;function W(t,e={}){const n=JSON.stringify([t,e]);let i=B.get(n);return void 0===i&&(i=new Intl.DateTimeFormat(t,e),B.set(n,i)),i}const U=new Map;const Y=new Map;let Z=null;const G=new Map;function K(t){let e=G.get(t);return void 0===e&&(e=new Intl.DateTimeFormat(t).resolvedOptions(),G.set(t,e)),e}const J=new Map;function X(t,e,n,i){const r=t.listingMode();return"error"===r?null:"en"===r?n(e):i(e)}class Q{constructor(t,e,n){this.padTo=n.padTo||0,this.floor=n.floor||!1;const{padTo:i,floor:r,...o}=n;if(!e||Object.keys(o).length>0){const e={useGrouping:!1,...n};n.padTo>0&&(e.minimumIntegerDigits=n.padTo),this.inf=function(t,e={}){const n=JSON.stringify([t,e]);let i=U.get(n);return void 0===i&&(i=new Intl.NumberFormat(t,e),U.set(n,i)),i}(t,e)}}format(t){if(this.inf){const e=this.floor?Math.floor(t):t;return this.inf.format(e)}return Ut(this.floor?Math.floor(t):Kt(t,3),this.padTo)}}class tt{constructor(t,e,n){let i;if(this.opts=n,this.originalZone=void 0,this.opts.timeZone)this.dt=t;else if("fixed"===t.zone.type){const e=t.offset/60*-1,n=e>=0?`Etc/GMT+${e}`:`Etc/GMT${e}`;0!==t.offset&&V.create(n).valid?(i=n,this.dt=t):(i="UTC",this.dt=0===t.offset?t:t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone)}else"system"===t.zone.type?this.dt=t:"iana"===t.zone.type?(this.dt=t,i=t.zone.name):(i="UTC",this.dt=t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone);const r={...this.opts};r.timeZone=r.timeZone||i,this.dtf=W(e,r)}format(){return this.originalZone?this.formatToParts().map(({value:t})=>t).join(""):this.dtf.format(this.dt.toJSDate())}formatToParts(){const t=this.dtf.formatToParts(this.dt.toJSDate());return this.originalZone?t.map(t=>{if("timeZoneName"===t.type){const e=this.originalZone.offsetName(this.dt.ts,{locale:this.dt.locale,format:this.opts.timeZoneName});return{...t,value:e}}return t}):t}resolvedOptions(){return this.dtf.resolvedOptions()}}class et{constructor(t,e,n){this.opts={style:"long",...n},!e&&qt()&&(this.rtf=function(t,e={}){const{base:n,...i}=e,r=JSON.stringify([t,i]);let o=Y.get(r);return void 0===o&&(o=new Intl.RelativeTimeFormat(t,e),Y.set(r,o)),o}(t,n))}format(t,e){return this.rtf?this.rtf.format(t,e):function(t,e,n="always",i=!1){const r={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."]},o=-1===["hours","minutes","seconds"].indexOf(t);if("auto"===n&&o){const n="days"===t;switch(e){case 1:return n?"tomorrow":`next ${r[t][0]}`;case-1:return n?"yesterday":`last ${r[t][0]}`;case 0:return n?"today":`this ${r[t][0]}`}}const s=Object.is(e,-0)||e<0,a=Math.abs(e),l=1===a,c=r[t],u=i?l?c[1]:c[2]||c[1]:l?r[t][0]:t;return s?`${a} ${u} ago`:`in ${a} ${u}`}(e,t,this.opts.numeric,"long"!==this.opts.style)}formatToParts(t,e){return this.rtf?this.rtf.formatToParts(t,e):[]}}const nt={firstDay:1,minimalDays:4,weekend:[6,7]};class it{static fromOpts(t){return it.create(t.locale,t.numberingSystem,t.outputCalendar,t.weekSettings,t.defaultToEN)}static create(t,e,n,i,r=!1){const o=t||wt.defaultLocale,s=o||(r?"en-US":Z||(Z=(new Intl.DateTimeFormat).resolvedOptions().locale,Z)),a=e||wt.defaultNumberingSystem,l=n||wt.defaultOutputCalendar,c=Bt(i)||wt.defaultWeekSettings;return new it(s,a,l,c,o)}static resetCache(){Z=null,B.clear(),U.clear(),Y.clear(),G.clear(),J.clear()}static fromObject({locale:t,numberingSystem:e,outputCalendar:n,weekSettings:i}={}){return it.create(t,e,n,i)}constructor(t,e,n,i,r){const[o,s,a]=function(t){const e=t.indexOf("-x-");-1!==e&&(t=t.substring(0,e));const n=t.indexOf("-u-");if(-1===n)return[t];{let e,i;try{e=W(t).resolvedOptions(),i=t}catch(r){const o=t.substring(0,n);e=W(o).resolvedOptions(),i=o}const{numberingSystem:r,calendar:o}=e;return[i,r,o]}}(t);this.locale=o,this.numberingSystem=e||s||null,this.outputCalendar=n||a||null,this.weekSettings=i,this.intl=function(t,e,n){return n||e?(t.includes("-u-")||(t+="-u"),n&&(t+=`-ca-${n}`),e&&(t+=`-nu-${e}`),t):t}(this.locale,this.numberingSystem,this.outputCalendar),this.weekdaysCache={format:{},standalone:{}},this.monthsCache={format:{},standalone:{}},this.meridiemCache=null,this.eraCache={},this.specifiedLocale=r,this.fastNumbersCached=null}get fastNumbers(){var t;return null==this.fastNumbersCached&&(this.fastNumbersCached=(!(t=this).numberingSystem||"latn"===t.numberingSystem)&&("latn"===t.numberingSystem||!t.locale||t.locale.startsWith("en")||"latn"===K(t.locale).numberingSystem)),this.fastNumbersCached}listingMode(){const t=this.isEnglish(),e=!(null!==this.numberingSystem&&"latn"!==this.numberingSystem||null!==this.outputCalendar&&"gregory"!==this.outputCalendar);return t&&e?"en":"intl"}clone(t){return t&&0!==Object.getOwnPropertyNames(t).length?it.create(t.locale||this.specifiedLocale,t.numberingSystem||this.numberingSystem,t.outputCalendar||this.outputCalendar,Bt(t.weekSettings)||this.weekSettings,t.defaultToEN||!1):this}redefaultToEN(t={}){return this.clone({...t,defaultToEN:!0})}redefaultToSystem(t={}){return this.clone({...t,defaultToEN:!1})}months(t,e=!1){return X(this,t,pe,()=>{const n="ja"===this.intl||this.intl.startsWith("ja-"),i=(e&=!n)?{month:t,day:"numeric"}:{month:t},r=e?"format":"standalone";if(!this.monthsCache[r][t]){const e=n?t=>this.dtFormatter(t,i).format():t=>this.extract(t,i,"month");this.monthsCache[r][t]=function(t){const e=[];for(let n=1;n<=12;n++){const i=bi.utc(2009,n,1);e.push(t(i))}return e}(e)}return this.monthsCache[r][t]})}weekdays(t,e=!1){return X(this,t,ve,()=>{const n=e?{weekday:t,year:"numeric",month:"long",day:"numeric"}:{weekday:t},i=e?"format":"standalone";return this.weekdaysCache[i][t]||(this.weekdaysCache[i][t]=function(t){const e=[];for(let n=1;n<=7;n++){const i=bi.utc(2016,11,13+n);e.push(t(i))}return e}(t=>this.extract(t,n,"weekday"))),this.weekdaysCache[i][t]})}meridiems(){return X(this,void 0,()=>ye,()=>{if(!this.meridiemCache){const t={hour:"numeric",hourCycle:"h12"};this.meridiemCache=[bi.utc(2016,11,13,9),bi.utc(2016,11,13,19)].map(e=>this.extract(e,t,"dayperiod"))}return this.meridiemCache})}eras(t){return X(this,t,ke,()=>{const e={era:t};return this.eraCache[t]||(this.eraCache[t]=[bi.utc(-40,1,1),bi.utc(2017,1,1)].map(t=>this.extract(t,e,"era"))),this.eraCache[t]})}extract(t,e,n){const i=this.dtFormatter(t,e).formatToParts().find(t=>t.type.toLowerCase()===n);return i?i.value:null}numberFormatter(t={}){return new Q(this.intl,t.forceSimple||this.fastNumbers,t)}dtFormatter(t,e={}){return new tt(t,this.intl,e)}relFormatter(t={}){return new et(this.intl,this.isEnglish(),t)}listFormatter(t={}){return function(t,e={}){const n=JSON.stringify([t,e]);let i=z[n];return i||(i=new Intl.ListFormat(t,e),z[n]=i),i}(this.intl,t)}isEnglish(){return"en"===this.locale||"en-us"===this.locale.toLowerCase()||K(this.intl).locale.startsWith("en-us")}getWeekSettings(){return this.weekSettings?this.weekSettings:Ht()?function(t){let e=J.get(t);if(!e){const n=new Intl.Locale(t);e="getWeekInfo"in n?n.getWeekInfo():n.weekInfo,"minimalDays"in e||(e={...nt,...e}),J.set(t,e)}return e}(this.locale):nt}getStartOfWeek(){return this.getWeekSettings().firstDay}getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays}getWeekendDays(){return this.getWeekSettings().weekend}equals(t){return this.locale===t.locale&&this.numberingSystem===t.numberingSystem&&this.outputCalendar===t.outputCalendar}toString(){return`Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`}}let rt=null;class ot extends F{static get utcInstance(){return null===rt&&(rt=new ot(0)),rt}static instance(t){return 0===t?ot.utcInstance:new ot(t)}static parseSpecifier(t){if(t){const e=t.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(e)return new ot(oe(e[1],e[2]))}return null}constructor(t){super(),this.fixed=t}get type(){return"fixed"}get name(){return 0===this.fixed?"UTC":`UTC${le(this.fixed,"narrow")}`}get ianaName(){return 0===this.fixed?"Etc/UTC":`Etc/GMT${le(-this.fixed,"narrow")}`}offsetName(){return this.name}formatOffset(t,e){return le(this.fixed,e)}get isUniversal(){return!0}offset(){return this.fixed}equals(t){return"fixed"===t.type&&t.fixed===this.fixed}get isValid(){return!0}}class st extends F{constructor(t){super(),this.zoneName=t}get type(){return"invalid"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(){return null}formatOffset(){return""}offset(){return NaN}equals(){return!1}get isValid(){return!1}}function at(t,e){if(jt(t)||null===t)return e;if(t instanceof F)return t;if("string"==typeof t){const n=t.toLowerCase();return"default"===n?e:"local"===n||"system"===n?R.instance:"utc"===n||"gmt"===n?ot.utcInstance:ot.parseSpecifier(n)||V.create(t)}return Rt(t)?ot.instance(t):"object"==typeof t&&"offset"in t&&"function"==typeof t.offset?t:new st(t)}const lt={arab:"[٠-٩]",arabext:"[۰-۹]",bali:"[᭐-᭙]",beng:"[০-৯]",deva:"[०-९]",fullwide:"[0-9]",gujr:"[૦-૯]",hanidec:"[〇|一|二|三|四|五|六|七|八|九]",khmr:"[០-៩]",knda:"[೦-೯]",laoo:"[໐-໙]",limb:"[᥆-᥏]",mlym:"[൦-൯]",mong:"[᠐-᠙]",mymr:"[၀-၉]",orya:"[୦-୯]",tamldec:"[௦-௯]",telu:"[౦-౯]",thai:"[๐-๙]",tibt:"[༠-༩]",latn:"\\d"},ct={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881]},ut=lt.hanidec.replace(/[\[|\]]/g,"").split("");const dt=new Map;function ht({numberingSystem:t},e=""){const n=t||"latn";let i=dt.get(n);void 0===i&&(i=new Map,dt.set(n,i));let r=i.get(e);return void 0===r&&(r=new RegExp(`${lt[n]}${e}`),i.set(e,r)),r}let pt,mt=()=>Date.now(),ft="system",gt=null,vt=null,yt=null,bt=60,_t=null;class wt{static get now(){return mt}static set now(t){mt=t}static set defaultZone(t){ft=t}static get defaultZone(){return at(ft,R.instance)}static get defaultLocale(){return gt}static set defaultLocale(t){gt=t}static get defaultNumberingSystem(){return vt}static set defaultNumberingSystem(t){vt=t}static get defaultOutputCalendar(){return yt}static set defaultOutputCalendar(t){yt=t}static get defaultWeekSettings(){return _t}static set defaultWeekSettings(t){_t=Bt(t)}static get twoDigitCutoffYear(){return bt}static set twoDigitCutoffYear(t){bt=t%100}static get throwOnInvalid(){return pt}static set throwOnInvalid(t){pt=t}static resetCaches(){it.resetCache(),V.resetCache(),bi.resetCache(),dt.clear()}}class kt{constructor(t,e){this.reason=t,this.explanation=e}toMessage(){return this.explanation?`${this.reason}: ${this.explanation}`:this.reason}}const Tt=[0,31,59,90,120,151,181,212,243,273,304,334],Et=[0,31,60,91,121,152,182,213,244,274,305,335];function St(t,e){return new kt("unit out of range",`you specified ${e} (of type ${typeof e}) as a ${t}, which is invalid`)}function xt(t,e,n){const i=new Date(Date.UTC(t,e-1,n));t<100&&t>=0&&i.setUTCFullYear(i.getUTCFullYear()-1900);const r=i.getUTCDay();return 0===r?7:r}function Dt(t,e,n){return n+(Jt(t)?Et:Tt)[e-1]}function Ot(t,e){const n=Jt(t)?Et:Tt,i=n.findIndex(t=>tne(i,e,n)?(l=i+1,c=1):l=i,{weekYear:l,weekNumber:c,weekday:a,...ce(t)}}function At(t,e=4,n=1){const{weekYear:i,weekNumber:r,weekday:o}=t,s=Lt(xt(i,1,e),n),a=Xt(i);let l,c=7*r+o-s-7+e;c<1?(l=i-1,c+=Xt(l)):c>a?(l=i+1,c-=Xt(i)):l=i;const{month:u,day:d}=Ot(l,c);return{year:l,month:u,day:d,...ce(t)}}function Mt(t){const{year:e,month:n,day:i}=t;return{year:e,ordinal:Dt(e,n,i),...ce(t)}}function It(t){const{year:e,ordinal:n}=t,{month:i,day:r}=Ot(e,n);return{year:e,month:i,day:r,...ce(t)}}function Nt(t,e){if(!jt(t.localWeekday)||!jt(t.localWeekNumber)||!jt(t.localWeekYear)){if(!jt(t.weekday)||!jt(t.weekNumber)||!jt(t.weekYear))throw new a("Cannot mix locale-based week fields with ISO-based week fields");return jt(t.localWeekday)||(t.weekday=t.localWeekday),jt(t.localWeekNumber)||(t.weekNumber=t.localWeekNumber),jt(t.localWeekYear)||(t.weekYear=t.localWeekYear),delete t.localWeekday,delete t.localWeekNumber,delete t.localWeekYear,{minDaysInFirstWeek:e.getMinDaysInFirstWeek(),startOfWeek:e.getStartOfWeek()}}return{minDaysInFirstWeek:4,startOfWeek:1}}function Pt(t){const e=$t(t.year),n=Wt(t.month,1,12),i=Wt(t.day,1,Qt(t.year,t.month));return e?n?!i&&St("day",t.day):St("month",t.month):St("year",t.year)}function Ft(t){const{hour:e,minute:n,second:i,millisecond:r}=t,o=Wt(e,0,23)||24===e&&0===n&&0===i&&0===r,s=Wt(n,0,59),a=Wt(i,0,59),l=Wt(r,0,999);return o?s?a?!l&&St("millisecond",r):St("second",i):St("minute",n):St("hour",e)}function jt(t){return void 0===t}function Rt(t){return"number"==typeof t}function $t(t){return"number"==typeof t&&t%1==0}function qt(){try{return"undefined"!=typeof Intl&&!!Intl.RelativeTimeFormat}catch(t){return!1}}function Ht(){try{return"undefined"!=typeof Intl&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype)}catch(t){return!1}}function Vt(t,e,n){if(0!==t.length)return t.reduce((t,i)=>{const r=[e(i),i];return t&&n(t[0],r[0])===t[0]?t:r},null)[1]}function zt(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function Bt(t){if(null==t)return null;if("object"!=typeof t)throw new c("Week settings must be an object");if(!Wt(t.firstDay,1,7)||!Wt(t.minimalDays,1,7)||!Array.isArray(t.weekend)||t.weekend.some(t=>!Wt(t,1,7)))throw new c("Invalid week settings");return{firstDay:t.firstDay,minimalDays:t.minimalDays,weekend:Array.from(t.weekend)}}function Wt(t,e,n){return $t(t)&&t>=e&&t<=n}function Ut(t,e=2){let n;return n=t<0?"-"+(""+-t).padStart(e,"0"):(""+t).padStart(e,"0"),n}function Yt(t){return jt(t)||null===t||""===t?void 0:parseInt(t,10)}function Zt(t){return jt(t)||null===t||""===t?void 0:parseFloat(t)}function Gt(t){if(!jt(t)&&null!==t&&""!==t){const e=1e3*parseFloat("0."+t);return Math.floor(e)}}function Kt(t,e,n="round"){const i=10**e;switch(n){case"expand":return t>0?Math.ceil(t*i)/i:Math.floor(t*i)/i;case"trunc":return Math.trunc(t*i)/i;case"round":return Math.round(t*i)/i;case"floor":return Math.floor(t*i)/i;case"ceil":return Math.ceil(t*i)/i;default:throw new RangeError(`Value rounding ${n} is out of range`)}}function Jt(t){return t%4==0&&(t%100!=0||t%400==0)}function Xt(t){return Jt(t)?366:365}function Qt(t,e){const n=function(t,e){return t-e*Math.floor(t/e)}(e-1,12)+1;return 2===n?Jt(t+(e-n)/12)?29:28:[31,null,31,30,31,30,31,31,30,31,30,31][n-1]}function te(t){let e=Date.UTC(t.year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond);return t.year<100&&t.year>=0&&(e=new Date(e),e.setUTCFullYear(t.year,t.month-1,t.day)),+e}function ee(t,e,n){return-Lt(xt(t,1,e),n)+e-1}function ne(t,e=4,n=1){const i=ee(t,e,n),r=ee(t+1,e,n);return(Xt(t)-i+r)/7}function ie(t){return t>99?t:t>wt.twoDigitCutoffYear?1900+t:2e3+t}function re(t,e,n,i=null){const r=new Date(t),o={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"};i&&(o.timeZone=i);const s={timeZoneName:e,...o},a=new Intl.DateTimeFormat(n,s).formatToParts(r).find(t=>"timezonename"===t.type.toLowerCase());return a?a.value:null}function oe(t,e){let n=parseInt(t,10);Number.isNaN(n)&&(n=0);const i=parseInt(e,10)||0;return 60*n+(n<0||Object.is(n,-0)?-i:i)}function se(t){const e=Number(t);if("boolean"==typeof t||""===t||!Number.isFinite(e))throw new c(`Invalid unit value ${t}`);return e}function ae(t,e){const n={};for(const i in t)if(zt(t,i)){const r=t[i];if(null==r)continue;n[e(i)]=se(r)}return n}function le(t,e){const n=Math.trunc(Math.abs(t/60)),i=Math.trunc(Math.abs(t%60)),r=t>=0?"+":"-";switch(e){case"short":return`${r}${Ut(n,2)}:${Ut(i,2)}`;case"narrow":return`${r}${n}${i>0?`:${i}`:""}`;case"techie":return`${r}${Ut(n,2)}${Ut(i,2)}`;default:throw new RangeError(`Value format ${e} is out of range for property format`)}}function ce(t){return function(t,e){return e.reduce((e,n)=>(e[n]=t[n],e),{})}(t,["hour","minute","second","millisecond"])}const ue=["January","February","March","April","May","June","July","August","September","October","November","December"],de=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],he=["J","F","M","A","M","J","J","A","S","O","N","D"];function pe(t){switch(t){case"narrow":return[...he];case"short":return[...de];case"long":return[...ue];case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null}}const me=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],fe=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],ge=["M","T","W","T","F","S","S"];function ve(t){switch(t){case"narrow":return[...ge];case"short":return[...fe];case"long":return[...me];case"numeric":return["1","2","3","4","5","6","7"];default:return null}}const ye=["AM","PM"],be=["Before Christ","Anno Domini"],_e=["BC","AD"],we=["B","A"];function ke(t){switch(t){case"narrow":return[...we];case"short":return[..._e];case"long":return[...be];default:return null}}function Te(t,e){let n="";for(const i of t)i.literal?n+=i.val:n+=e(i.val);return n}const Ee={D:m,DD:f,DDD:v,DDDD:y,t:b,tt:_,ttt:w,tttt:k,T:T,TT:E,TTT:S,TTTT:x,f:D,ff:L,fff:M,ffff:N,F:O,FF:C,FFF:I,FFFF:P};class Se{static create(t,e={}){return new Se(t,e)}static parseFormat(t){let e=null,n="",i=!1;const r=[];for(let o=0;o0||i)&&r.push({literal:i||/^\s+$/.test(n),val:""===n?"'":n}),e=null,n="",i=!i):i||s===e?n+=s:(n.length>0&&r.push({literal:/^\s+$/.test(n),val:n}),n=s,e=s)}return n.length>0&&r.push({literal:i||/^\s+$/.test(n),val:n}),r}static macroTokenToFormatOpts(t){return Ee[t]}constructor(t,e){this.opts=e,this.loc=t,this.systemLoc=null}formatWithSystemDefault(t,e){null===this.systemLoc&&(this.systemLoc=this.loc.redefaultToSystem());return this.systemLoc.dtFormatter(t,{...this.opts,...e}).format()}dtFormatter(t,e={}){return this.loc.dtFormatter(t,{...this.opts,...e})}formatDateTime(t,e){return this.dtFormatter(t,e).format()}formatDateTimeParts(t,e){return this.dtFormatter(t,e).formatToParts()}formatInterval(t,e){return this.dtFormatter(t.start,e).dtf.formatRange(t.start.toJSDate(),t.end.toJSDate())}resolvedOptions(t,e){return this.dtFormatter(t,e).resolvedOptions()}num(t,e=0,n=void 0){if(this.opts.forceSimple)return Ut(t,e);const i={...this.opts};return e>0&&(i.padTo=e),n&&(i.signDisplay=n),this.loc.numberFormatter(i).format(t)}formatDateTimeFromString(t,e){const n="en"===this.loc.listingMode(),i=this.loc.outputCalendar&&"gregory"!==this.loc.outputCalendar,r=(e,n)=>this.loc.extract(t,e,n),o=e=>t.isOffsetFixed&&0===t.offset&&e.allowZ?"Z":t.isValid?t.zone.formatOffset(t.ts,e.format):"",s=()=>n?function(t){return ye[t.hour<12?0:1]}(t):r({hour:"numeric",hourCycle:"h12"},"dayperiod"),a=(e,i)=>n?function(t,e){return pe(e)[t.month-1]}(t,e):r(i?{month:e}:{month:e,day:"numeric"},"month"),l=(e,i)=>n?function(t,e){return ve(e)[t.weekday-1]}(t,e):r(i?{weekday:e}:{weekday:e,month:"long",day:"numeric"},"weekday"),c=e=>{const n=Se.macroTokenToFormatOpts(e);return n?this.formatWithSystemDefault(t,n):e},u=e=>n?function(t,e){return ke(e)[t.year<0?0:1]}(t,e):r({era:e},"era");return Te(Se.parseFormat(e),e=>{switch(e){case"S":return this.num(t.millisecond);case"u":case"SSS":return this.num(t.millisecond,3);case"s":return this.num(t.second);case"ss":return this.num(t.second,2);case"uu":return this.num(Math.floor(t.millisecond/10),2);case"uuu":return this.num(Math.floor(t.millisecond/100));case"m":return this.num(t.minute);case"mm":return this.num(t.minute,2);case"h":return this.num(t.hour%12==0?12:t.hour%12);case"hh":return this.num(t.hour%12==0?12:t.hour%12,2);case"H":return this.num(t.hour);case"HH":return this.num(t.hour,2);case"Z":return o({format:"narrow",allowZ:this.opts.allowZ});case"ZZ":return o({format:"short",allowZ:this.opts.allowZ});case"ZZZ":return o({format:"techie",allowZ:this.opts.allowZ});case"ZZZZ":return t.zone.offsetName(t.ts,{format:"short",locale:this.loc.locale});case"ZZZZZ":return t.zone.offsetName(t.ts,{format:"long",locale:this.loc.locale});case"z":return t.zoneName;case"a":return s();case"d":return i?r({day:"numeric"},"day"):this.num(t.day);case"dd":return i?r({day:"2-digit"},"day"):this.num(t.day,2);case"c":case"E":return this.num(t.weekday);case"ccc":return l("short",!0);case"cccc":return l("long",!0);case"ccccc":return l("narrow",!0);case"EEE":return l("short",!1);case"EEEE":return l("long",!1);case"EEEEE":return l("narrow",!1);case"L":return i?r({month:"numeric",day:"numeric"},"month"):this.num(t.month);case"LL":return i?r({month:"2-digit",day:"numeric"},"month"):this.num(t.month,2);case"LLL":return a("short",!0);case"LLLL":return a("long",!0);case"LLLLL":return a("narrow",!0);case"M":return i?r({month:"numeric"},"month"):this.num(t.month);case"MM":return i?r({month:"2-digit"},"month"):this.num(t.month,2);case"MMM":return a("short",!1);case"MMMM":return a("long",!1);case"MMMMM":return a("narrow",!1);case"y":return i?r({year:"numeric"},"year"):this.num(t.year);case"yy":return i?r({year:"2-digit"},"year"):this.num(t.year.toString().slice(-2),2);case"yyyy":return i?r({year:"numeric"},"year"):this.num(t.year,4);case"yyyyyy":return i?r({year:"numeric"},"year"):this.num(t.year,6);case"G":return u("short");case"GG":return u("long");case"GGGGG":return u("narrow");case"kk":return this.num(t.weekYear.toString().slice(-2),2);case"kkkk":return this.num(t.weekYear,4);case"W":return this.num(t.weekNumber);case"WW":return this.num(t.weekNumber,2);case"n":return this.num(t.localWeekNumber);case"nn":return this.num(t.localWeekNumber,2);case"ii":return this.num(t.localWeekYear.toString().slice(-2),2);case"iiii":return this.num(t.localWeekYear,4);case"o":return this.num(t.ordinal);case"ooo":return this.num(t.ordinal,3);case"q":return this.num(t.quarter);case"qq":return this.num(t.quarter,2);case"X":return this.num(Math.floor(t.ts/1e3));case"x":return this.num(t.ts);default:return c(e)}})}formatDurationFromString(t,e){const n="negativeLargestOnly"===this.opts.signMode?-1:1,i=t=>{switch(t[0]){case"S":return"milliseconds";case"s":return"seconds";case"m":return"minutes";case"h":return"hours";case"d":return"days";case"w":return"weeks";case"M":return"months";case"y":return"years";default:return null}},r=Se.parseFormat(e),o=r.reduce((t,{literal:e,val:n})=>e?t:t.concat(n),[]),s=t.shiftTo(...o.map(i).filter(t=>t));return Te(r,((t,e)=>r=>{const o=i(r);if(o){const i=e.isNegativeDuration&&o!==e.largestUnit?n:1;let s;return s="negativeLargestOnly"===this.opts.signMode&&o!==e.largestUnit?"never":"all"===this.opts.signMode?"always":"auto",this.num(t.get(o)*i,r.length,s)}return r})(s,{isNegativeDuration:s<0,largestUnit:Object.keys(s.values)[0]}))}}const xe=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function De(...t){const e=t.reduce((t,e)=>t+e.source,"");return RegExp(`^${e}$`)}function Oe(...t){return e=>t.reduce(([t,n,i],r)=>{const[o,s,a]=r(e,i);return[{...t,...o},s||n,a]},[{},null,1]).slice(0,2)}function Le(t,...e){if(null==t)return[null,null];for(const[n,i]of e){const e=n.exec(t);if(e)return i(e)}return[null,null]}function Ce(...t){return(e,n)=>{const i={};let r;for(r=0;rvoid 0!==t&&(e||t&&u)?-t:t;return[{years:h(Zt(n)),months:h(Zt(i)),weeks:h(Zt(r)),days:h(Zt(o)),hours:h(Zt(s)),minutes:h(Zt(a)),seconds:h(Zt(l),"-0"===l),milliseconds:h(Gt(c),d)}]}const Ue={GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ye(t,e,n,i,r,o,s){const a={year:2===e.length?ie(Yt(e)):Yt(e),month:de.indexOf(n)+1,day:Yt(i),hour:Yt(r),minute:Yt(o)};return s&&(a.second=Yt(s)),t&&(a.weekday=t.length>3?me.indexOf(t)+1:fe.indexOf(t)+1),a}const Ze=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function Ge(t){const[,e,n,i,r,o,s,a,l,c,u,d]=t,h=Ye(e,r,i,n,o,s,a);let p;return p=l?Ue[l]:c?0:oe(u,d),[h,new ot(p)]}const Ke=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,Je=/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,Xe=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function Qe(t){const[,e,n,i,r,o,s,a]=t;return[Ye(e,r,i,n,o,s,a),ot.utcInstance]}function tn(t){const[,e,n,i,r,o,s,a]=t;return[Ye(e,a,n,i,r,o,s),ot.utcInstance]}const en=De(/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/,Ne),nn=De(/(\d{4})-?W(\d\d)(?:-?(\d))?/,Ne),rn=De(/(\d{4})-?(\d{3})/,Ne),on=De(Ie),sn=Oe(function(t,e){return[{year:$e(t,e),month:$e(t,e+1,1),day:$e(t,e+2,1)},null,e+3]},qe,He,Ve),an=Oe(Pe,qe,He,Ve),ln=Oe(Fe,qe,He,Ve),cn=Oe(qe,He,Ve);const un=Oe(qe);const dn=De(/(\d{4})-(\d\d)-(\d\d)/,Re),hn=De(je),pn=Oe(qe,He,Ve);const mn="Invalid Duration",fn={weeks:{days:7,hours:168,minutes:10080,seconds:604800,milliseconds:6048e5},days:{hours:24,minutes:1440,seconds:86400,milliseconds:864e5},hours:{minutes:60,seconds:3600,milliseconds:36e5},minutes:{seconds:60,milliseconds:6e4},seconds:{milliseconds:1e3}},gn={years:{quarters:4,months:12,weeks:52,days:365,hours:8760,minutes:525600,seconds:31536e3,milliseconds:31536e6},quarters:{months:3,weeks:13,days:91,hours:2184,minutes:131040,seconds:7862400,milliseconds:78624e5},months:{weeks:4,days:30,hours:720,minutes:43200,seconds:2592e3,milliseconds:2592e6},...fn},vn=365.2425,yn=30.436875,bn={years:{quarters:4,months:12,weeks:52.1775,days:vn,hours:8765.82,minutes:525949.2,seconds:525949.2*60,milliseconds:525949.2*60*1e3},quarters:{months:3,weeks:13.044375,days:91.310625,hours:2191.455,minutes:131487.3,seconds:525949.2*60/4,milliseconds:7889237999.999999},months:{weeks:4.3481250000000005,days:yn,hours:730.485,minutes:43829.1,seconds:2629746,milliseconds:2629746e3},...fn},_n=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds"],wn=_n.slice(0).reverse();function kn(t,e,n=!1){const i={values:n?e.values:{...t.values,...e.values||{}},loc:t.loc.clone(e.loc),conversionAccuracy:e.conversionAccuracy||t.conversionAccuracy,matrix:e.matrix||t.matrix};return new xn(i)}function Tn(t,e){let n=e.milliseconds??0;for(const i of wn.slice(1))e[i]&&(n+=e[i]*t[i].milliseconds);return n}function En(t,e){const n=Tn(t,e)<0?-1:1;_n.reduceRight((i,r)=>{if(jt(e[r]))return i;if(i){const o=e[i]*n,s=t[r][i],a=Math.floor(o/s);e[r]+=a*n,e[i]-=a*s*n}return r},null),_n.reduce((n,i)=>{if(jt(e[i]))return n;if(n){const r=e[n]%1;e[n]-=r,e[i]+=r*t[n][i]}return i},null)}function Sn(t){const e={};for(const[n,i]of Object.entries(t))0!==i&&(e[n]=i);return e}class xn{constructor(t){const e="longterm"===t.conversionAccuracy||!1;let n=e?bn:gn;t.matrix&&(n=t.matrix),this.values=t.values,this.loc=t.loc||it.create(),this.conversionAccuracy=e?"longterm":"casual",this.invalid=t.invalid||null,this.matrix=n,this.isLuxonDuration=!0}static fromMillis(t,e){return xn.fromObject({milliseconds:t},e)}static fromObject(t,e={}){if(null==t||"object"!=typeof t)throw new c("Duration.fromObject: argument expected to be an object, got "+(null===t?"null":typeof t));return new xn({values:ae(t,xn.normalizeUnit),loc:it.fromObject(e),conversionAccuracy:e.conversionAccuracy,matrix:e.matrix})}static fromDurationLike(t){if(Rt(t))return xn.fromMillis(t);if(xn.isDuration(t))return t;if("object"==typeof t)return xn.fromObject(t);throw new c(`Unknown duration argument ${t} of type ${typeof t}`)}static fromISO(t,e){const[n]=function(t){return Le(t,[Be,We])}(t);return n?xn.fromObject(n,e):xn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static fromISOTime(t,e){const[n]=function(t){return Le(t,[ze,un])}(t);return n?xn.fromObject(n,e):xn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Duration is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new s(n);return new xn({invalid:n})}static normalizeUnit(t){const e={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds"}[t?t.toLowerCase():t];if(!e)throw new l(t);return e}static isDuration(t){return t&&t.isLuxonDuration||!1}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}toFormat(t,e={}){const n={...e,floor:!1!==e.round&&!1!==e.floor};return this.isValid?Se.create(this.loc,n).formatDurationFromString(this,t):mn}toHuman(t={}){if(!this.isValid)return mn;const e=!1!==t.showZeros,n=_n.map(n=>{const i=this.values[n];return jt(i)||0===i&&!e?null:this.loc.numberFormatter({style:"unit",unitDisplay:"long",...t,unit:n.slice(0,-1)}).format(i)}).filter(t=>t);return this.loc.listFormatter({type:"conjunction",style:t.listStyle||"narrow",...t}).format(n)}toObject(){return this.isValid?{...this.values}:{}}toISO(){if(!this.isValid)return null;let t="P";return 0!==this.years&&(t+=this.years+"Y"),0===this.months&&0===this.quarters||(t+=this.months+3*this.quarters+"M"),0!==this.weeks&&(t+=this.weeks+"W"),0!==this.days&&(t+=this.days+"D"),0===this.hours&&0===this.minutes&&0===this.seconds&&0===this.milliseconds||(t+="T"),0!==this.hours&&(t+=this.hours+"H"),0!==this.minutes&&(t+=this.minutes+"M"),0===this.seconds&&0===this.milliseconds||(t+=Kt(this.seconds+this.milliseconds/1e3,3)+"S"),"P"===t&&(t+="T0S"),t}toISOTime(t={}){if(!this.isValid)return null;const e=this.toMillis();if(e<0||e>=864e5)return null;t={suppressMilliseconds:!1,suppressSeconds:!1,includePrefix:!1,format:"extended",...t,includeOffset:!1};return bi.fromMillis(e,{zone:"UTC"}).toISOTime(t)}toJSON(){return this.toISO()}toString(){return this.toISO()}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Duration { values: ${JSON.stringify(this.values)} }`:`Duration { Invalid, reason: ${this.invalidReason} }`}toMillis(){return this.isValid?Tn(this.matrix,this.values):NaN}valueOf(){return this.toMillis()}plus(t){if(!this.isValid)return this;const e=xn.fromDurationLike(t),n={};for(const t of _n)(zt(e.values,t)||zt(this.values,t))&&(n[t]=e.get(t)+this.get(t));return kn(this,{values:n},!0)}minus(t){if(!this.isValid)return this;const e=xn.fromDurationLike(t);return this.plus(e.negate())}mapUnits(t){if(!this.isValid)return this;const e={};for(const n of Object.keys(this.values))e[n]=se(t(this.values[n],n));return kn(this,{values:e},!0)}get(t){return this[xn.normalizeUnit(t)]}set(t){if(!this.isValid)return this;return kn(this,{values:{...this.values,...ae(t,xn.normalizeUnit)}})}reconfigure({locale:t,numberingSystem:e,conversionAccuracy:n,matrix:i}={}){return kn(this,{loc:this.loc.clone({locale:t,numberingSystem:e}),matrix:i,conversionAccuracy:n})}as(t){return this.isValid?this.shiftTo(t).get(t):NaN}normalize(){if(!this.isValid)return this;const t=this.toObject();return En(this.matrix,t),kn(this,{values:t},!0)}rescale(){if(!this.isValid)return this;return kn(this,{values:Sn(this.normalize().shiftToAll().toObject())},!0)}shiftTo(...t){if(!this.isValid)return this;if(0===t.length)return this;t=t.map(t=>xn.normalizeUnit(t));const e={},n={},i=this.toObject();let r;for(const o of _n)if(t.indexOf(o)>=0){r=o;let t=0;for(const e in n)t+=this.matrix[e][o]*n[e],n[e]=0;Rt(i[o])&&(t+=i[o]);const s=Math.trunc(t);e[o]=s,n[o]=(1e3*t-1e3*s)/1e3}else Rt(i[o])&&(n[o]=i[o]);for(const t in n)0!==n[t]&&(e[r]+=t===r?n[t]:n[t]/this.matrix[r][t]);return En(this.matrix,e),kn(this,{values:e},!0)}shiftToAll(){return this.isValid?this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds"):this}negate(){if(!this.isValid)return this;const t={};for(const e of Object.keys(this.values))t[e]=0===this.values[e]?0:-this.values[e];return kn(this,{values:t},!0)}removeZeros(){if(!this.isValid)return this;return kn(this,{values:Sn(this.values)},!0)}get years(){return this.isValid?this.values.years||0:NaN}get quarters(){return this.isValid?this.values.quarters||0:NaN}get months(){return this.isValid?this.values.months||0:NaN}get weeks(){return this.isValid?this.values.weeks||0:NaN}get days(){return this.isValid?this.values.days||0:NaN}get hours(){return this.isValid?this.values.hours||0:NaN}get minutes(){return this.isValid?this.values.minutes||0:NaN}get seconds(){return this.isValid?this.values.seconds||0:NaN}get milliseconds(){return this.isValid?this.values.milliseconds||0:NaN}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}equals(t){if(!this.isValid||!t.isValid)return!1;if(!this.loc.equals(t.loc))return!1;function e(t,e){return void 0===t||0===t?void 0===e||0===e:t===e}for(const n of _n)if(!e(this.values[n],t.values[n]))return!1;return!0}}const Dn="Invalid Interval";class On{constructor(t){this.s=t.start,this.e=t.end,this.invalid=t.invalid||null,this.isLuxonInterval=!0}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Interval is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new o(n);return new On({invalid:n})}static fromDateTimes(t,e){const n=_i(t),i=_i(e),r=function(t,e){return t&&t.isValid?e&&e.isValid?et}isBefore(t){return!!this.isValid&&this.e<=t}contains(t){return!!this.isValid&&(this.s<=t&&this.e>t)}set({start:t,end:e}={}){return this.isValid?On.fromDateTimes(t||this.s,e||this.e):this}splitAt(...t){if(!this.isValid)return[];const e=t.map(_i).filter(t=>this.contains(t)).sort((t,e)=>t.toMillis()-e.toMillis()),n=[];let{s:i}=this,r=0;for(;i+this.e?this.e:t;n.push(On.fromDateTimes(i,o)),i=o,r+=1}return n}splitBy(t){const e=xn.fromDurationLike(t);if(!this.isValid||!e.isValid||0===e.as("milliseconds"))return[];let n,{s:i}=this,r=1;const o=[];for(;it*r));n=+t>+this.e?this.e:t,o.push(On.fromDateTimes(i,n)),i=n,r+=1}return o}divideEqually(t){return this.isValid?this.splitBy(this.length()/t).slice(0,t):[]}overlaps(t){return this.e>t.s&&this.s=t.e)}equals(t){return!(!this.isValid||!t.isValid)&&(this.s.equals(t.s)&&this.e.equals(t.e))}intersection(t){if(!this.isValid)return this;const e=this.s>t.s?this.s:t.s,n=this.e=n?null:On.fromDateTimes(e,n)}union(t){if(!this.isValid)return this;const e=this.st.e?this.e:t.e;return On.fromDateTimes(e,n)}static merge(t){const[e,n]=t.sort((t,e)=>t.s-e.s).reduce(([t,e],n)=>e?e.overlaps(n)||e.abutsStart(n)?[t,e.union(n)]:[t.concat([e]),n]:[t,n],[[],null]);return n&&e.push(n),e}static xor(t){let e=null,n=0;const i=[],r=t.map(t=>[{time:t.s,type:"s"},{time:t.e,type:"e"}]),o=Array.prototype.concat(...r).sort((t,e)=>t.time-e.time);for(const t of o)n+="s"===t.type?1:-1,1===n?e=t.time:(e&&+e!==+t.time&&i.push(On.fromDateTimes(e,t.time)),e=null);return On.merge(i)}difference(...t){return On.xor([this].concat(t)).map(t=>this.intersection(t)).filter(t=>t&&!t.isEmpty())}toString(){return this.isValid?`[${this.s.toISO()} – ${this.e.toISO()})`:Dn}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`:`Interval { Invalid, reason: ${this.invalidReason} }`}toLocaleString(t=m,e={}){return this.isValid?Se.create(this.s.loc.clone(e),t).formatInterval(this):Dn}toISO(t){return this.isValid?`${this.s.toISO(t)}/${this.e.toISO(t)}`:Dn}toISODate(){return this.isValid?`${this.s.toISODate()}/${this.e.toISODate()}`:Dn}toISOTime(t){return this.isValid?`${this.s.toISOTime(t)}/${this.e.toISOTime(t)}`:Dn}toFormat(t,{separator:e=" – "}={}){return this.isValid?`${this.s.toFormat(t)}${e}${this.e.toFormat(t)}`:Dn}toDuration(t,e){return this.isValid?this.e.diff(this.s,t,e):xn.invalid(this.invalidReason)}mapEndpoints(t){return On.fromDateTimes(t(this.s),t(this.e))}}class Ln{static hasDST(t=wt.defaultZone){const e=bi.now().setZone(t).set({month:12});return!t.isUniversal&&e.offset!==e.set({month:6}).offset}static isValidIANAZone(t){return V.isValidZone(t)}static normalizeZone(t){return at(t,wt.defaultZone)}static getStartOfWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getStartOfWeek()}static getMinimumDaysInFirstWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getMinDaysInFirstWeek()}static getWeekendWeekdays({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getWeekendDays().slice()}static months(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:r="gregory"}={}){return(i||it.create(e,n,r)).months(t)}static monthsFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:r="gregory"}={}){return(i||it.create(e,n,r)).months(t,!0)}static weekdays(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t)}static weekdaysFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t,!0)}static meridiems({locale:t=null}={}){return it.create(t).meridiems()}static eras(t="short",{locale:e=null}={}){return it.create(e,null,"gregory").eras(t)}static features(){return{relative:qt(),localeWeek:Ht()}}}function Cn(t,e){const n=t=>t.toUTC(0,{keepLocalTime:!0}).startOf("day").valueOf(),i=n(e)-n(t);return Math.floor(xn.fromMillis(i).as("days"))}function An(t,e,n,i){let[r,o,s,a]=function(t,e,n){const i=[["years",(t,e)=>e.year-t.year],["quarters",(t,e)=>e.quarter-t.quarter+4*(e.year-t.year)],["months",(t,e)=>e.month-t.month+12*(e.year-t.year)],["weeks",(t,e)=>{const n=Cn(t,e);return(n-n%7)/7}],["days",Cn]],r={},o=t;let s,a;for(const[l,c]of i)n.indexOf(l)>=0&&(s=l,r[l]=c(t,e),a=o.plus(r),a>e?(r[l]--,(t=o.plus(r))>e&&(a=t,r[l]--,t=o.plus(r))):t=a);return[t,r,a,s]}(t,e,n);const l=e-r,c=n.filter(t=>["hours","minutes","seconds","milliseconds"].indexOf(t)>=0);0===c.length&&(s0?xn.fromMillis(l,i).shiftTo(...c).plus(u):u}function Mn(t,e=t=>t){return{regex:t,deser:([t])=>e(function(t){let e=parseInt(t,10);if(isNaN(e)){e="";for(let n=0;n=n&&i<=r&&(e+=i-n)}}return parseInt(e,10)}return e}(t))}}const In=`[ ${String.fromCharCode(160)}]`,Nn=new RegExp(In,"g");function Pn(t){return t.replace(/\./g,"\\.?").replace(Nn,In)}function Fn(t){return t.replace(/\./g,"").replace(Nn," ").toLowerCase()}function jn(t,e){return null===t?null:{regex:RegExp(t.map(Pn).join("|")),deser:([n])=>t.findIndex(t=>Fn(n)===Fn(t))+e}}function Rn(t,e){return{regex:t,deser:([,t,e])=>oe(t,e),groups:e}}function $n(t){return{regex:t,deser:([t])=>t}}const qn={year:{"2-digit":"yy",numeric:"yyyyy"},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM"},day:{numeric:"d","2-digit":"dd"},weekday:{short:"EEE",long:"EEEE"},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh"},hour24:{numeric:"H","2-digit":"HH"},minute:{numeric:"m","2-digit":"mm"},second:{numeric:"s","2-digit":"ss"},timeZoneName:{long:"ZZZZZ",short:"ZZZ"}};let Hn=null;function Vn(t,e){return Array.prototype.concat(...t.map(t=>function(t,e){if(t.literal)return t;const n=Wn(Se.macroTokenToFormatOpts(t.val),e);return null==n||n.includes(void 0)?t:n}(t,e)))}class zn{constructor(t,e){if(this.locale=t,this.format=e,this.tokens=Vn(Se.parseFormat(e),t),this.units=this.tokens.map(e=>function(t,e){const n=ht(e),i=ht(e,"{2}"),r=ht(e,"{3}"),o=ht(e,"{4}"),s=ht(e,"{6}"),a=ht(e,"{1,2}"),l=ht(e,"{1,3}"),c=ht(e,"{1,6}"),u=ht(e,"{1,9}"),d=ht(e,"{2,4}"),h=ht(e,"{4,6}"),p=t=>{return{regex:RegExp((e=t.val,e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"))),deser:([t])=>t,literal:!0};var e},m=(m=>{if(t.literal)return p(m);switch(m.val){case"G":return jn(e.eras("short"),0);case"GG":return jn(e.eras("long"),0);case"y":return Mn(c);case"yy":case"kk":return Mn(d,ie);case"yyyy":case"kkkk":return Mn(o);case"yyyyy":return Mn(h);case"yyyyyy":return Mn(s);case"M":case"L":case"d":case"H":case"h":case"m":case"q":case"s":case"W":return Mn(a);case"MM":case"LL":case"dd":case"HH":case"hh":case"mm":case"qq":case"ss":case"WW":return Mn(i);case"MMM":return jn(e.months("short",!0),1);case"MMMM":return jn(e.months("long",!0),1);case"LLL":return jn(e.months("short",!1),1);case"LLLL":return jn(e.months("long",!1),1);case"o":case"S":return Mn(l);case"ooo":case"SSS":return Mn(r);case"u":return $n(u);case"uu":return $n(a);case"uuu":case"E":case"c":return Mn(n);case"a":return jn(e.meridiems(),0);case"EEE":return jn(e.weekdays("short",!1),1);case"EEEE":return jn(e.weekdays("long",!1),1);case"ccc":return jn(e.weekdays("short",!0),1);case"cccc":return jn(e.weekdays("long",!0),1);case"Z":case"ZZ":return Rn(new RegExp(`([+-]${a.source})(?::(${i.source}))?`),2);case"ZZZ":return Rn(new RegExp(`([+-]${a.source})(${i.source})?`),2);case"z":return $n(/[a-z_+-/]{1,256}?/i);case" ":return $n(/[^\S\n\r]/);default:return p(m)}})(t)||{invalidReason:"missing Intl.DateTimeFormat.formatToParts support"};return m.token=t,m}(e,t)),this.disqualifyingUnit=this.units.find(t=>t.invalidReason),!this.disqualifyingUnit){const[t,e]=[`^${(n=this.units).map(t=>t.regex).reduce((t,e)=>`${t}(${e.source})`,"")}$`,n];this.regex=RegExp(t,"i"),this.handlers=e}var n}explainFromTokens(t){if(this.isValid){const[e,n]=function(t,e,n){const i=t.match(e);if(i){const t={};let e=1;for(const r in n)if(zt(n,r)){const o=n[r],s=o.groups?o.groups+1:1;!o.literal&&o.token&&(t[o.token.val[0]]=o.deser(i.slice(e,e+s))),e+=s}return[i,t]}return[i,{}]}(t,this.regex,this.handlers),[i,r,o]=n?function(t){let e,n=null;return jt(t.z)||(n=V.create(t.z)),jt(t.Z)||(n||(n=new ot(t.Z)),e=t.Z),jt(t.q)||(t.M=3*(t.q-1)+1),jt(t.h)||(t.h<12&&1===t.a?t.h+=12:12===t.h&&0===t.a&&(t.h=0)),0===t.G&&t.y&&(t.y=-t.y),jt(t.u)||(t.S=Gt(t.u)),[Object.keys(t).reduce((e,n)=>{const i=(t=>{switch(t){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null}})(n);return i&&(e[i]=t[n]),e},{}),n,e]}(n):[null,null,void 0];if(zt(n,"a")&&zt(n,"H"))throw new a("Can't include meridiem when specifying 24-hour format");return{input:t,tokens:this.tokens,regex:this.regex,rawMatches:e,matches:n,result:i,zone:r,specificOffset:o}}return{input:t,tokens:this.tokens,invalidReason:this.invalidReason}}get isValid(){return!this.disqualifyingUnit}get invalidReason(){return this.disqualifyingUnit?this.disqualifyingUnit.invalidReason:null}}function Bn(t,e,n){return new zn(t,n).explainFromTokens(e)}function Wn(t,e){if(!t)return null;const n=Se.create(e,t).dtFormatter((Hn||(Hn=bi.fromMillis(1555555555555)),Hn)),i=n.formatToParts(),r=n.resolvedOptions();return i.map(e=>function(t,e,n){const{type:i,value:r}=t;if("literal"===i){const t=/^\s+$/.test(r);return{literal:!t,val:t?" ":r}}const o=e[i];let s=i;"hour"===i&&(s=null!=e.hour12?e.hour12?"hour12":"hour24":null!=e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle?"hour12":"hour24":n.hour12?"hour12":"hour24");let a=qn[s];if("object"==typeof a&&(a=a[o]),a)return{literal:!1,val:a}}(e,t,r))}const Un="Invalid DateTime",Yn=864e13;function Zn(t){return new kt("unsupported zone",`the zone "${t.name}" is not supported`)}function Gn(t){return null===t.weekData&&(t.weekData=Ct(t.c)),t.weekData}function Kn(t){return null===t.localWeekData&&(t.localWeekData=Ct(t.c,t.loc.getMinDaysInFirstWeek(),t.loc.getStartOfWeek())),t.localWeekData}function Jn(t,e){const n={ts:t.ts,zone:t.zone,c:t.c,o:t.o,loc:t.loc,invalid:t.invalid};return new bi({...n,...e,old:n})}function Xn(t,e,n){let i=t-60*e*1e3;const r=n.offset(i);if(e===r)return[i,e];i-=60*(r-e)*1e3;const o=n.offset(i);return r===o?[i,r]:[t-60*Math.min(r,o)*1e3,Math.max(r,o)]}function Qn(t,e){const n=new Date(t+=60*e*1e3);return{year:n.getUTCFullYear(),month:n.getUTCMonth()+1,day:n.getUTCDate(),hour:n.getUTCHours(),minute:n.getUTCMinutes(),second:n.getUTCSeconds(),millisecond:n.getUTCMilliseconds()}}function ti(t,e,n){return Xn(te(t),e,n)}function ei(t,e){const n=t.o,i=t.c.year+Math.trunc(e.years),r=t.c.month+Math.trunc(e.months)+3*Math.trunc(e.quarters),o={...t.c,year:i,month:r,day:Math.min(t.c.day,Qt(i,r))+Math.trunc(e.days)+7*Math.trunc(e.weeks)},s=xn.fromObject({years:e.years-Math.trunc(e.years),quarters:e.quarters-Math.trunc(e.quarters),months:e.months-Math.trunc(e.months),weeks:e.weeks-Math.trunc(e.weeks),days:e.days-Math.trunc(e.days),hours:e.hours,minutes:e.minutes,seconds:e.seconds,milliseconds:e.milliseconds}).as("milliseconds"),a=te(o);let[l,c]=Xn(a,n,t.zone);return 0!==s&&(l+=s,c=t.zone.offset(l)),{ts:l,o:c}}function ni(t,e,n,i,r,o){const{setZone:s,zone:a}=n;if(t&&0!==Object.keys(t).length||e){const i=e||a,r=bi.fromObject(t,{...n,zone:i,specificOffset:o});return s?r:r.setZone(a)}return bi.invalid(new kt("unparsable",`the input "${r}" can't be parsed as ${i}`))}function ii(t,e,n=!0){return t.isValid?Se.create(it.create("en-US"),{allowZ:n,forceSimple:!0}).formatDateTimeFromString(t,e):null}function ri(t,e,n){const i=t.c.year>9999||t.c.year<0;let r="";if(i&&t.c.year>=0&&(r+="+"),r+=Ut(t.c.year,i?6:4),"year"===n)return r;if(e){if(r+="-",r+=Ut(t.c.month),"month"===n)return r;r+="-"}else if(r+=Ut(t.c.month),"month"===n)return r;return r+=Ut(t.c.day),r}function oi(t,e,n,i,r,o,s){let a=!n||0!==t.c.millisecond||0!==t.c.second,l="";switch(s){case"day":case"month":case"year":break;default:if(l+=Ut(t.c.hour),"hour"===s)break;if(e){if(l+=":",l+=Ut(t.c.minute),"minute"===s)break;a&&(l+=":",l+=Ut(t.c.second))}else{if(l+=Ut(t.c.minute),"minute"===s)break;a&&(l+=Ut(t.c.second))}if("second"===s)break;!a||i&&0===t.c.millisecond||(l+=".",l+=Ut(t.c.millisecond,3))}return r&&(t.isOffsetFixed&&0===t.offset&&!o?l+="Z":t.o<0?(l+="-",l+=Ut(Math.trunc(-t.o/60)),l+=":",l+=Ut(Math.trunc(-t.o%60))):(l+="+",l+=Ut(Math.trunc(t.o/60)),l+=":",l+=Ut(Math.trunc(t.o%60)))),o&&(l+="["+t.zone.ianaName+"]"),l}const si={month:1,day:1,hour:0,minute:0,second:0,millisecond:0},ai={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0},li={ordinal:1,hour:0,minute:0,second:0,millisecond:0},ci=["year","month","day","hour","minute","second","millisecond"],ui=["weekYear","weekNumber","weekday","hour","minute","second","millisecond"],di=["year","ordinal","hour","minute","second","millisecond"];function hi(t){const e={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal"}[t.toLowerCase()];if(!e)throw new l(t);return e}function pi(t){switch(t.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return hi(t)}}function mi(t,e){const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e);let r,o;if(jt(t.year))r=wt.now();else{for(const e of ci)jt(t[e])&&(t[e]=si[e]);const e=Pt(t)||Ft(t);if(e)return bi.invalid(e);const i=function(t){if(void 0===vi&&(vi=wt.now()),"iana"!==t.type)return t.offset(vi);const e=t.name;let n=yi.get(e);return void 0===n&&(n=t.offset(vi),yi.set(e,n)),n}(n);[r,o]=ti(t,i,n)}return new bi({ts:r,zone:n,loc:i,o:o})}function fi(t,e,n){const i=!!jt(n.round)||n.round,r=jt(n.rounding)?"trunc":n.rounding,o=(t,o)=>{t=Kt(t,i||n.calendary?0:2,n.calendary?"round":r);return e.loc.clone(n).relFormatter(n).format(t,o)},s=i=>n.calendary?e.hasSame(t,i)?0:e.startOf(i).diff(t.startOf(i),i).get(i):e.diff(t,i).get(i);if(n.unit)return o(s(n.unit),n.unit);for(const t of n.units){const e=s(t);if(Math.abs(e)>=1)return o(e,t)}return o(t>e?-0:0,n.units[n.units.length-1])}function gi(t){let e,n={};return t.length>0&&"object"==typeof t[t.length-1]?(n=t[t.length-1],e=Array.from(t).slice(0,t.length-1)):e=Array.from(t),[n,e]}let vi;const yi=new Map;class bi{constructor(t){const e=t.zone||wt.defaultZone;let n=t.invalid||(Number.isNaN(t.ts)?new kt("invalid input"):null)||(e.isValid?null:Zn(e));this.ts=jt(t.ts)?wt.now():t.ts;let i=null,r=null;if(!n){if(t.old&&t.old.ts===this.ts&&t.old.zone.equals(e))[i,r]=[t.old.c,t.old.o];else{const o=Rt(t.o)&&!t.old?t.o:e.offset(this.ts);i=Qn(this.ts,o),n=Number.isNaN(i.year)?new kt("invalid input"):null,i=n?null:i,r=n?null:o}}this._zone=e,this.loc=t.loc||it.create(),this.invalid=n,this.weekData=null,this.localWeekData=null,this.c=i,this.o=r,this.isLuxonDateTime=!0}static now(){return new bi({})}static local(){const[t,e]=gi(arguments),[n,i,r,o,s,a,l]=e;return mi({year:n,month:i,day:r,hour:o,minute:s,second:a,millisecond:l},t)}static utc(){const[t,e]=gi(arguments),[n,i,r,o,s,a,l]=e;return t.zone=ot.utcInstance,mi({year:n,month:i,day:r,hour:o,minute:s,second:a,millisecond:l},t)}static fromJSDate(t,e={}){const n=(i=t,"[object Date]"===Object.prototype.toString.call(i)?t.valueOf():NaN);var i;if(Number.isNaN(n))return bi.invalid("invalid input");const r=at(e.zone,wt.defaultZone);return r.isValid?new bi({ts:n,zone:r,loc:it.fromObject(e)}):bi.invalid(Zn(r))}static fromMillis(t,e={}){if(Rt(t))return t<-Yn||t>Yn?bi.invalid("Timestamp out of range"):new bi({ts:t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c(`fromMillis requires a numerical input, but received a ${typeof t} with value ${t}`)}static fromSeconds(t,e={}){if(Rt(t))return new bi({ts:1e3*t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c("fromSeconds requires a numerical input")}static fromObject(t,e={}){t=t||{};const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e),r=ae(t,pi),{minDaysInFirstWeek:o,startOfWeek:s}=Nt(r,i),l=wt.now(),c=jt(e.specificOffset)?n.offset(l):e.specificOffset,u=!jt(r.ordinal),d=!jt(r.year),h=!jt(r.month)||!jt(r.day),p=d||h,m=r.weekYear||r.weekNumber;if((p||u)&&m)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(h&&u)throw new a("Can't mix ordinal dates with month/day");const f=m||r.weekday&&!p;let g,v,y=Qn(l,c);f?(g=ui,v=ai,y=Ct(y,o,s)):u?(g=di,v=li,y=Mt(y)):(g=ci,v=si);let b=!1;for(const t of g){jt(r[t])?r[t]=b?v[t]:y[t]:b=!0}const _=f?function(t,e=4,n=1){const i=$t(t.weekYear),r=Wt(t.weekNumber,1,ne(t.weekYear,e,n)),o=Wt(t.weekday,1,7);return i?r?!o&&St("weekday",t.weekday):St("week",t.weekNumber):St("weekYear",t.weekYear)}(r,o,s):u?function(t){const e=$t(t.year),n=Wt(t.ordinal,1,Xt(t.year));return e?!n&&St("ordinal",t.ordinal):St("year",t.year)}(r):Pt(r),w=_||Ft(r);if(w)return bi.invalid(w);const k=f?At(r,o,s):u?It(r):r,[T,E]=ti(k,c,n),S=new bi({ts:T,zone:n,o:E,loc:i});return r.weekday&&p&&t.weekday!==S.weekday?bi.invalid("mismatched weekday",`you can't specify both a weekday of ${r.weekday} and a date of ${S.toISO()}`):S.isValid?S:bi.invalid(S.invalid)}static fromISO(t,e={}){const[n,i]=function(t){return Le(t,[en,sn],[nn,an],[rn,ln],[on,cn])}(t);return ni(n,i,e,"ISO 8601",t)}static fromRFC2822(t,e={}){const[n,i]=function(t){return Le(function(t){return t.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim()}(t),[Ze,Ge])}(t);return ni(n,i,e,"RFC 2822",t)}static fromHTTP(t,e={}){const[n,i]=function(t){return Le(t,[Ke,Qe],[Je,Qe],[Xe,tn])}(t);return ni(n,i,e,"HTTP",e)}static fromFormat(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormat requires an input string and a format");const{locale:i=null,numberingSystem:r=null}=n,o=it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0}),[s,a,l,u]=function(t,e,n){const{result:i,zone:r,specificOffset:o,invalidReason:s}=Bn(t,e,n);return[i,r,o,s]}(o,t,e);return u?bi.invalid(u):ni(s,a,n,`format ${e}`,t,l)}static fromString(t,e,n={}){return bi.fromFormat(t,e,n)}static fromSQL(t,e={}){const[n,i]=function(t){return Le(t,[dn,sn],[hn,pn])}(t);return ni(n,i,e,"SQL",t)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the DateTime is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new r(n);return new bi({invalid:n})}static isDateTime(t){return t&&t.isLuxonDateTime||!1}static parseFormatForOpts(t,e={}){const n=Wn(t,it.fromObject(e));return n?n.map(t=>t?t.val:null).join(""):null}static expandFormat(t,e={}){return Vn(Se.parseFormat(t),it.fromObject(e)).map(t=>t.val).join("")}static resetCache(){vi=void 0,yi.clear()}get(t){return this[t]}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}get outputCalendar(){return this.isValid?this.loc.outputCalendar:null}get zone(){return this._zone}get zoneName(){return this.isValid?this.zone.name:null}get year(){return this.isValid?this.c.year:NaN}get quarter(){return this.isValid?Math.ceil(this.c.month/3):NaN}get month(){return this.isValid?this.c.month:NaN}get day(){return this.isValid?this.c.day:NaN}get hour(){return this.isValid?this.c.hour:NaN}get minute(){return this.isValid?this.c.minute:NaN}get second(){return this.isValid?this.c.second:NaN}get millisecond(){return this.isValid?this.c.millisecond:NaN}get weekYear(){return this.isValid?Gn(this).weekYear:NaN}get weekNumber(){return this.isValid?Gn(this).weekNumber:NaN}get weekday(){return this.isValid?Gn(this).weekday:NaN}get isWeekend(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday)}get localWeekday(){return this.isValid?Kn(this).weekday:NaN}get localWeekNumber(){return this.isValid?Kn(this).weekNumber:NaN}get localWeekYear(){return this.isValid?Kn(this).weekYear:NaN}get ordinal(){return this.isValid?Mt(this.c).ordinal:NaN}get monthShort(){return this.isValid?Ln.months("short",{locObj:this.loc})[this.month-1]:null}get monthLong(){return this.isValid?Ln.months("long",{locObj:this.loc})[this.month-1]:null}get weekdayShort(){return this.isValid?Ln.weekdays("short",{locObj:this.loc})[this.weekday-1]:null}get weekdayLong(){return this.isValid?Ln.weekdays("long",{locObj:this.loc})[this.weekday-1]:null}get offset(){return this.isValid?+this.o:NaN}get offsetNameShort(){return this.isValid?this.zone.offsetName(this.ts,{format:"short",locale:this.locale}):null}get offsetNameLong(){return this.isValid?this.zone.offsetName(this.ts,{format:"long",locale:this.locale}):null}get isOffsetFixed(){return this.isValid?this.zone.isUniversal:null}get isInDST(){return!this.isOffsetFixed&&(this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset)}getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed)return[this];const t=864e5,e=6e4,n=te(this.c),i=this.zone.offset(n-t),r=this.zone.offset(n+t),o=this.zone.offset(n-i*e),s=this.zone.offset(n-r*e);if(o===s)return[this];const a=n-o*e,l=n-s*e,c=Qn(a,o),u=Qn(l,s);return c.hour===u.hour&&c.minute===u.minute&&c.second===u.second&&c.millisecond===u.millisecond?[Jn(this,{ts:a}),Jn(this,{ts:l})]:[this]}get isInLeapYear(){return Jt(this.year)}get daysInMonth(){return Qt(this.year,this.month)}get daysInYear(){return this.isValid?Xt(this.year):NaN}get weeksInWeekYear(){return this.isValid?ne(this.weekYear):NaN}get weeksInLocalWeekYear(){return this.isValid?ne(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN}resolvedLocaleOptions(t={}){const{locale:e,numberingSystem:n,calendar:i}=Se.create(this.loc.clone(t),t).resolvedOptions(this);return{locale:e,numberingSystem:n,outputCalendar:i}}toUTC(t=0,e={}){return this.setZone(ot.instance(t),e)}toLocal(){return this.setZone(wt.defaultZone)}setZone(t,{keepLocalTime:e=!1,keepCalendarTime:n=!1}={}){if((t=at(t,wt.defaultZone)).equals(this.zone))return this;if(t.isValid){let i=this.ts;if(e||n){const e=t.offset(this.ts),n=this.toObject();[i]=ti(n,e,t)}return Jn(this,{ts:i,zone:t})}return bi.invalid(Zn(t))}reconfigure({locale:t,numberingSystem:e,outputCalendar:n}={}){return Jn(this,{loc:this.loc.clone({locale:t,numberingSystem:e,outputCalendar:n})})}setLocale(t){return this.reconfigure({locale:t})}set(t){if(!this.isValid)return this;const e=ae(t,pi),{minDaysInFirstWeek:n,startOfWeek:i}=Nt(e,this.loc),r=!jt(e.weekYear)||!jt(e.weekNumber)||!jt(e.weekday),o=!jt(e.ordinal),s=!jt(e.year),l=!jt(e.month)||!jt(e.day),c=s||l,u=e.weekYear||e.weekNumber;if((c||o)&&u)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(l&&o)throw new a("Can't mix ordinal dates with month/day");let d;r?d=At({...Ct(this.c,n,i),...e},n,i):jt(e.ordinal)?(d={...this.toObject(),...e},jt(e.day)&&(d.day=Math.min(Qt(d.year,d.month),d.day))):d=It({...Mt(this.c),...e});const[h,p]=ti(d,this.o,this.zone);return Jn(this,{ts:h,o:p})}plus(t){if(!this.isValid)return this;return Jn(this,ei(this,xn.fromDurationLike(t)))}minus(t){if(!this.isValid)return this;return Jn(this,ei(this,xn.fromDurationLike(t).negate()))}startOf(t,{useLocaleWeeks:e=!1}={}){if(!this.isValid)return this;const n={},i=xn.normalizeUnit(t);switch(i){case"years":n.month=1;case"quarters":case"months":n.day=1;case"weeks":case"days":n.hour=0;case"hours":n.minute=0;case"minutes":n.second=0;case"seconds":n.millisecond=0}if("weeks"===i)if(e){const t=this.loc.getStartOfWeek(),{weekday:e}=this;e=3&&(a+="T"),a+=oi(this,s,e,n,i,r,o),a}toISODate({format:t="extended",precision:e="day"}={}){return this.isValid?ri(this,"extended"===t,hi(e)):null}toISOWeekDate(){return ii(this,"kkkk-'W'WW-c")}toISOTime({suppressMilliseconds:t=!1,suppressSeconds:e=!1,includeOffset:n=!0,includePrefix:i=!1,extendedZone:r=!1,format:o="extended",precision:s="milliseconds"}={}){if(!this.isValid)return null;return s=hi(s),(i&&ci.indexOf(s)>=3?"T":"")+oi(this,"extended"===o,e,t,n,r,s)}toRFC2822(){return ii(this,"EEE, dd LLL yyyy HH:mm:ss ZZZ",!1)}toHTTP(){return ii(this.toUTC(),"EEE, dd LLL yyyy HH:mm:ss 'GMT'")}toSQLDate(){return this.isValid?ri(this,!0):null}toSQLTime({includeOffset:t=!0,includeZone:e=!1,includeOffsetSpace:n=!0}={}){let i="HH:mm:ss.SSS";return(e||t)&&(n&&(i+=" "),e?i+="z":t&&(i+="ZZ")),ii(this,i,!0)}toSQL(t={}){return this.isValid?`${this.toSQLDate()} ${this.toSQLTime(t)}`:null}toString(){return this.isValid?this.toISO():Un}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`:`DateTime { Invalid, reason: ${this.invalidReason} }`}valueOf(){return this.toMillis()}toMillis(){return this.isValid?this.ts:NaN}toSeconds(){return this.isValid?this.ts/1e3:NaN}toUnixInteger(){return this.isValid?Math.floor(this.ts/1e3):NaN}toJSON(){return this.toISO()}toBSON(){return this.toJSDate()}toObject(t={}){if(!this.isValid)return{};const e={...this.c};return t.includeConfig&&(e.outputCalendar=this.outputCalendar,e.numberingSystem=this.loc.numberingSystem,e.locale=this.loc.locale),e}toJSDate(){return new Date(this.isValid?this.ts:NaN)}diff(t,e="milliseconds",n={}){if(!this.isValid||!t.isValid)return xn.invalid("created by diffing an invalid DateTime");const i={locale:this.locale,numberingSystem:this.numberingSystem,...n},r=(a=e,Array.isArray(a)?a:[a]).map(xn.normalizeUnit),o=t.valueOf()>this.valueOf(),s=An(o?this:t,o?t:this,r,i);var a;return o?s.negate():s}diffNow(t="milliseconds",e={}){return this.diff(bi.now(),t,e)}until(t){return this.isValid?On.fromDateTimes(this,t):this}hasSame(t,e,n){if(!this.isValid)return!1;const i=t.valueOf(),r=this.setZone(t.zone,{keepLocalTime:!0});return r.startOf(e,n)<=i&&i<=r.endOf(e,n)}equals(t){return this.isValid&&t.isValid&&this.valueOf()===t.valueOf()&&this.zone.equals(t.zone)&&this.loc.equals(t.loc)}toRelative(t={}){if(!this.isValid)return null;const e=t.base||bi.fromObject({},{zone:this.zone}),n=t.padding?thist.valueOf(),Math.min)}static max(...t){if(!t.every(bi.isDateTime))throw new c("max requires all arguments be DateTimes");return Vt(t,t=>t.valueOf(),Math.max)}static fromFormatExplain(t,e,n={}){const{locale:i=null,numberingSystem:r=null}=n;return Bn(it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0}),t,e)}static fromStringExplain(t,e,n={}){return bi.fromFormatExplain(t,e,n)}static buildFormatParser(t,e={}){const{locale:n=null,numberingSystem:i=null}=e,r=it.fromOpts({locale:n,numberingSystem:i,defaultToEN:!0});return new zn(r,t)}static fromFormatParser(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormatParser requires an input string and a format parser");const{locale:i=null,numberingSystem:r=null}=n,o=it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0});if(!o.equals(e.locale))throw new c(`fromFormatParser called with a locale of ${o}, but the format parser was created for ${e.locale}`);const{result:s,zone:a,specificOffset:l,invalidReason:u}=e.explainFromTokens(t);return u?bi.invalid(u):ni(s,a,n,`format ${e.format}`,t,l)}static get DATE_SHORT(){return m}static get DATE_MED(){return f}static get DATE_MED_WITH_WEEKDAY(){return g}static get DATE_FULL(){return v}static get DATE_HUGE(){return y}static get TIME_SIMPLE(){return b}static get TIME_WITH_SECONDS(){return _}static get TIME_WITH_SHORT_OFFSET(){return w}static get TIME_WITH_LONG_OFFSET(){return k}static get TIME_24_SIMPLE(){return T}static get TIME_24_WITH_SECONDS(){return E}static get TIME_24_WITH_SHORT_OFFSET(){return S}static get TIME_24_WITH_LONG_OFFSET(){return x}static get DATETIME_SHORT(){return D}static get DATETIME_SHORT_WITH_SECONDS(){return O}static get DATETIME_MED(){return L}static get DATETIME_MED_WITH_SECONDS(){return C}static get DATETIME_MED_WITH_WEEKDAY(){return A}static get DATETIME_FULL(){return M}static get DATETIME_FULL_WITH_SECONDS(){return I}static get DATETIME_HUGE(){return N}static get DATETIME_HUGE_WITH_SECONDS(){return P}}function _i(t){if(bi.isDateTime(t))return t;if(t&&t.valueOf&&Rt(t.valueOf()))return bi.fromJSDate(t);if(t&&"object"==typeof t)return bi.fromObject(t);throw new c(`Unknown datetime argument: ${t}, of type ${typeof t}`)}}},function(t){var e;e=7368,t(t.s=e)}]); \ No newline at end of file diff --git a/public/build/app.77b6dec9.js.LICENSE.txt b/public/build/app.4f8430f7.js.LICENSE.txt similarity index 100% rename from public/build/app.77b6dec9.js.LICENSE.txt rename to public/build/app.4f8430f7.js.LICENSE.txt diff --git a/public/build/app.77b6dec9.js b/public/build/app.77b6dec9.js deleted file mode 100644 index c13f6cd7..00000000 --- a/public/build/app.77b6dec9.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see app.77b6dec9.js.LICENSE.txt */ -(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[524],{7368:function(t,e,n){n(3829),n(6833),n.g.KimaiPaginatedBoxWidget=n(7648).A,n.g.KimaiReloadPageWidget=n(1630).A,n.g.KimaiColor=n(9790).A,n.g.KimaiStorage=n(4667).A},6833:function(t,e,n){"use strict";var i=n(2647);class r{constructor(t){this._translations=t}get(t){return this._translations[t]}has(t){return t in this._translations}}class o{constructor(t){this._configurations=t}get(t){return this._configurations[t]}has(t){return t in this._configurations}isRTL(){return"rtl"===this.get("direction")}getLanguage(){return this.get("locale").replace("_","-")}is24Hours(){return!!this.get("twentyFourHours")}getFirstDayOfWeek(t=!0){void 0===t&&(t=!0);let e=this.get("first_dow_iso");return t||(e%=7),e}}n(9690);class s{init(){}getId(){return null}setContainer(t){if(!(t instanceof a))throw new Error("Plugin was given an invalid KimaiContainer");this._core=t}getContainer(){return this._core}getConfiguration(t){return this.getContainer().getConfiguration().get(t)}getConfigurations(){return this.getContainer().getConfiguration()}getDateUtils(){return this.getPlugin("date")}getPlugin(t){return this.getContainer().getPlugin(t)}getTranslation(){return this.getContainer().getTranslation()}translate(t){return this.getTranslation().get(t)}escape(t){return this.getPlugin("escape").escapeForHtml(t)}trigger(t,e=null){this.getPlugin("event").trigger(t,e)}fetch(t,e={}){return this.getPlugin("fetch").fetch(t,e)}fetchForm(t,e={},n=null){n=n||t.getAttribute("action");const i=t.getAttribute("method").toUpperCase();if("GET"===i){const i=this.getPlugin("form").convertFormDataToQueryString(t,{},!0);n=n+(n.includes("?")?"&":"?")+i,e={method:"GET",...e}}else"POST"===i&&(e={method:"POST",body:new FormData(t),...e});return this.fetch(n,e)}isMobile(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)<576}}class a{constructor(t,e){if(!(t instanceof o))throw new Error("Configuration needs to a KimaiConfiguration instance");if(this._configuration=t,!(e instanceof r))throw new Error("Configuration needs to a KimaiTranslation instance");this._translation=e,this._plugins=[]}registerPlugin(t){if(!(t instanceof s))throw new Error("Invalid plugin given, needs to be a KimaiPlugin instance");return t.setContainer(this),this._plugins.push(t),t}getPlugin(t){for(let e of this._plugins)if(null!==e.getId()&&e.getId()===t)return e;throw new Error("Unknown plugin: "+t)}getPlugins(){return this._plugins}getTranslation(){return this._translation}getConfiguration(){return this._configuration}getUser(){return this.getPlugin("user")}}class l extends s{constructor(t){super(),this.dataAttribute=t}getId(){return"datatable-column-visibility"}init(){let t=document.querySelector("["+this.dataAttribute+"]");if(null!==t){this._id=t.getAttribute(this.dataAttribute),this._modal=document.getElementById("modal_"+this._id),this._modal.addEventListener("show.bs.modal",()=>{this._evaluateCheckboxes()}),this._modal.querySelector("button[data-type=save]").addEventListener("click",()=>{this._saveVisibility()}),this._modal.querySelector("button[data-type=reset]").addEventListener("click",t=>{this._resetVisibility(t.currentTarget)}),this._modal.querySelectorAll("input[name=datatable_profile]").forEach(t=>{t.addEventListener("change",()=>{const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("data-href")).then(()=>{localStorage.setItem("kimai_profile",t.getAttribute("value")),document.location.reload()}).catch(()=>{e.setAttribute("action",t.getAttribute("data-href")),e.submit()})})});for(let t of this._modal.querySelectorAll("form input[type=checkbox]"))t.addEventListener("change",()=>{this._changeVisibility(t.getAttribute("name"),t.checked)})}}_evaluateCheckboxes(){const t=this._modal.getElementsByTagName("form")[0],e=document.getElementsByClassName("datatable_"+this._id)[0];for(let n of e.getElementsByTagName("th")){const e=n.getAttribute("data-field");if(null===e)continue;const i=t.querySelector("input[name="+e+"]");null!==i&&(i.checked="none"!==window.getComputedStyle(n).display)}}_saveVisibility(){const t=this._modal.getElementsByTagName("form")[0];this.fetchForm(t).then(()=>{document.location.reload()}).catch(()=>{t.submit()})}_resetVisibility(t){const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("formaction")).then(()=>{document.location.reload()}).catch(()=>{e.setAttribute("action",t.getAttribute("formaction")),e.submit()})}_changeVisibility(t,e){for(const n of document.getElementsByClassName("datatable_"+this._id)){let i=null;for(let r of n.getElementsByClassName("col_"+t)){if(null===i){let t="-none",n="d-table-cell";e||(t="-table-cell",n="d-none"),i="",r.classList.forEach(function(e,n,r){-1===e.indexOf(t)&&(i+=" "+e)}),-1===i.indexOf(n)&&(i+=" "+n)}r.className=i}}}}var c=n(6318);class u extends s{init(){[].slice.call(document.querySelectorAll('[data-toggle="tooltip"]')).map(function(t){return new c.m_(t)});[...document.querySelectorAll(".offcanvas")].map(t=>new c.go(t));this.getContainer().getPlugin("form").activateForm("div.page-wrapper form"),this._registerModalAutofocus("#remote_form_modal"),this.overlay=null,document.addEventListener("kimai.reloadContent",t=>{if(null!==this.overlay)return;let e="div.page-wrapper";void 0!==t.detail&&null!==t.detail&&(e=t.detail);const n=document.createElement("div");n.innerHTML='
',this.overlay=n.firstElementChild,document.querySelector(e).append(this.overlay)}),document.addEventListener("kimai.reloadedContent",()=>{null!==this.overlay&&(this.overlay.remove(),this.overlay=null)})}_registerModalAutofocus(t){if(this.isMobile())return;const e=document.querySelector(t);null!==e&&e.addEventListener("shown.bs.modal",()=>{const t=e.querySelector("form");let n=t.querySelectorAll("[autofocus]");n.length<1&&(n=t.querySelectorAll("input[type=text],input[type=date],textarea,select")),n.length>0&&n[0].focus()})}}var d=n(837);n(6311);class h extends s{supportsForm(t){return!1}activateForm(t){}destroyForm(t){}}class p extends h{constructor(t){super(),this._selector=t}init(){window.disableLitepickerStyles=!0,this._pickers=[]}supportsForm(t){return!0}activateForm(t){const e=this.getConfigurations().getFirstDayOfWeek(!1),n=this.getConfigurations().getLanguage();let i={buttonText:{previousMonth:'',nextMonth:'',apply:this.translate("confirm"),cancel:this.translate("cancel")}};const r=[].slice.call(t.querySelectorAll(this._selector)).map(t=>(void 0===t.dataset.format&&console.log("Trying to bind litepicker to an element without data-format attribute"),void 0!==t.hasAttribute("min")&&(i={...i,minDate:t.getAttribute("min")}),void 0!==t.hasAttribute("max")&&(i={...i,maxDate:t.getAttribute("max")}),i={...i,format:t.dataset.format,showTooltip:!1,element:t,lang:n,autoRefresh:!0,firstDay:e,setup:e=>{e.on("preselect",(t,n)=>{e._wasPreselected=!0}),e.on("selected",(n,i)=>{void 0!==e._wasPreselected&&(t.dispatchEvent(new Event("change",{bubbles:!0})),delete e._wasPreselected)}),void 0!==e.backdrop&&document.body.appendChild(e.backdrop)}},[t,new d.Litepicker(this.prepareOptions(i))]));this._pickers=this._pickers.concat(r)}prepareOptions(t){return{...t,plugins:["mobilefriendly"]}}destroyForm(t){[].slice.call(t.querySelectorAll(this._selector)).map(t=>{for(let e=0;e{this.reloadDatatable()};for(let t of e.split(" "))document.addEventListener(t,n);document.addEventListener("pagination-change",n),document.addEventListener("filter-change",n)}registerContextMenu(t){f.A.createForDataTable(t)}reloadDatatable(){const t=this.getContainer().getPlugin("toolbar").getSelector(),e=document.querySelector(t),n=t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector(this._contentArea);document.querySelector(this._contentArea).replaceWith(n),this.registerContextMenu(this._selector),document.dispatchEvent(new Event("kimai.reloadedContent"))};document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this._contentArea})),null!==e?this.fetchForm(e).then(t=>{t.text().then(n)}).catch(()=>{e.submit()}):this.fetch(document.location).then(t=>{t.text().then(n)}).catch(()=>{document.location.reload()})}}class v extends s{constructor(t,e){super(),this._formSelector=t,this._actionClass=e}getId(){return"toolbar"}init(){const t=this.getSelector();this._registerPagination(t),this._registerSortableTables(t),this._registerAlternativeSubmitActions(t,this._actionClass),[].slice.call(document.querySelectorAll(t+" input")).map(e=>{e.addEventListener("change",e=>{switch(e.target.id){case"order":case"orderBy":case"page":break;default:document.querySelector(t+" input#page").value=1}}),this.triggerChange()}),[].slice.call(document.querySelectorAll(t+" select")).map(e=>{e.addEventListener("change",e=>{let n=!0;switch(e.target.id){case"customer":null!==document.querySelector(t+" select#project")&&(n=!1);break;case"project":null!==document.querySelector(t+" select#activity")&&(n=!1)}document.querySelector(t+" input#page").value=1,n&&this.triggerChange()})})}_registerAlternativeSubmitActions(t,e){document.addEventListener("click",function(n){let i=n.target;for(;null!==i&&"function"==typeof i.matches&&!i.matches("body");){if(i.classList.contains(e)){const e=document.querySelector(t);if(null===e)return;const r=e.getAttribute("action"),o=e.getAttribute("method");void 0!==i.dataset.target&&(e.target=i.dataset.target),e.action=i.href,void 0!==i.dataset.method&&(e.method=i.dataset.method),e.submit(),e.target="",e.action=r,e.method=o,n.preventDefault(),n.stopPropagation()}i=i.parentNode}})}_registerSortableTables(t){document.body.addEventListener("click",e=>{if(!e.target.matches("th.sortable"))return;let n="DESC",i=e.target.dataset.order;e.target.classList.contains("sorting_desc")&&(n="ASC"),document.querySelector(t+" #orderBy").value=i,document.querySelector(t+" #order").value=n,document.querySelector(t+" #orderBy").dispatchEvent(new Event("change")),document.querySelector(t+" #order").dispatchEvent(new Event("change")),document.dispatchEvent(new Event("filter-change"))})}_registerPagination(t){document.body.addEventListener("click",e=>{if(!(e.target.matches("ul.pagination li a")||null!==e.target.parentNode&&e.target.parentNode.matches("ul.pagination li a")))return;let n=document.querySelector(t+" input#page");if(null===n)return;let i=e.target;i.matches("a")||(i=i.parentNode),e.preventDefault(),e.stopPropagation();let r=i.href.split("/"),o=r[r.length-1];return/\d/.test(o)||(o=1),n.value=o,n.dispatchEvent(new Event("change")),document.dispatchEvent(new Event("pagination-change")),!1})}triggerChange(){document.dispatchEvent(new Event("toolbar-change"))}getSelector(){return this._formSelector}}class y extends s{getId(){return"api"}_headers(){const t=new Headers;return t.append("Content-Type","application/json"),t}get(t,e,n,i){if(void 0!==e){const n=new URLSearchParams(e).toString();""!==n&&(t=t+(t.includes("?")?"&":"?")+n)}void 0===i&&(i=t=>{this.handleError("An error occurred",t)}),this.fetch(t,{method:"GET",headers:this._headers()}).then(t=>{t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}post(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"POST",body:this._parseData(e),headers:this._headers()}).then(t=>{t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}patch(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"PATCH",body:this._parseData(e),headers:this._headers()}).then(t=>{204===t.statusCode?n():t.json().then(t=>{n(t)})}).catch(t=>{i(t)})}delete(t,e,n){void 0===n&&(n=t=>{this.handleError("action.delete.error",t)}),this.fetch(t,{method:"DELETE",headers:this._headers()}).then(()=>{e()}).catch(t=>{n(t)})}_parseData(t){return"object"==typeof t?JSON.stringify(t):t}handleError(t,e){if(void 0===e.headers)return;const n=e.headers.get("content-type");n&&-1!==n.indexOf("application/json")?e.json().then(n=>{let i=n.message;if(400===e.status&&n.errors){let t=[""+i+""];if(n.errors.errors)for(let e of n.errors.errors)t.push(e);if(n.errors.children)for(let e in n.errors.children){let i=n.errors.children[e];if(void 0!==i.errors&&i.errors.length>0)for(let e of i.errors)t.push(e)}t.length>0&&(i=t)}this.getPlugin("alert").error(t,i)}):e.text().then(()=>{const n="["+e.statusCode+"] "+e.statusText;this.getPlugin("alert").error(t,n)})}}class b extends s{addClickHandler(t,e,n){document.body.addEventListener("click",i=>{let r=i.target;for(;null!==r;){const e=r.tagName.toUpperCase();if("BODY"===e)return;if(r.matches(t))break;if("A"===e||"BUTTON"===e||"INPUT"===e||"LABEL"===e)return;for(let t of n)if(r.matches(t))return;r=r.parentNode}if(null===r)return;if(r.isContentEditable||r.parentNode.isContentEditable)return;if(!r.matches(t))return;for(let t of n)if(r.matches(t))return;i.preventDefault(),i.stopPropagation();let o=r.dataset.href;null==o&&(o=r.href),null!=o&&""!==o&&e(o)})}}class _ extends b{constructor(t){super(),this._selector=t}init(){this.addClickHandler(this._selector,function(t){window.location=t},[])}}class w extends b{constructor(t,e){super(),this._selector=t,this._stopSelector=e}getId(){return"modal"}init(){this._isDirty=!1;const t=this._getModalElement();null!==t&&(t.addEventListener("hide.bs.modal",e=>{if(this._isDirty){if(null===t.querySelector(".modal-body .remote_modal_is_dirty_warning")){const e=this.translate("modal.dirty"),n=document.createElement("div");n.innerHTML='

'+e+"

",t.querySelector(".modal-body").prepend(n.firstElementChild)}e.preventDefault()}else this._isDirty=!1,document.dispatchEvent(new Event("modal-hide"))}),t.addEventListener("hidden.bs.modal",()=>{this.getContainer().getPlugin("form").destroyForm(this._getFormIdentifier()),t.querySelector(".modal-body").replaceWith("")}),t.addEventListener("show.bs.modal",()=>{document.dispatchEvent(new Event("modal-show"))}),this.addClickHandler(this._selector,t=>{this.openUrlInModal(t)},this._stopSelector))}_getModal(){return c.aF.getOrCreateInstance(this._getModalElement())}openUrlInModal(t,e){const n=new Headers;n.append("X-Requested-With","Kimai-Modal"),this.fetch(t,{method:"GET",redirect:"follow",headers:n}).then(e=>{if(e.ok)return e.text().then(t=>{this._openFormInModal(t)});window.location=t}).catch(n=>{null==e?window.location=t:e(n)})}_getFormIdentifier(){return"#remote_form_modal .modal-content form"}_getModalElement(){return document.getElementById("remote_form_modal")}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}_openFormInModal(t){const e=this._getFormIdentifier();let n=this._getModalElement();const i=document.createElement("div");i.innerHTML=t;const r=this._makeScriptExecutable(i.querySelector("#form_modal .modal-content"));if(null!==r){let t=n.querySelector(".modal-dialog"),o=i.querySelector(".modal-dialog").classList.contains("modal-lg");o&&!t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),!o&&t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),n.querySelector(".modal-content").replaceWith(r),[].slice.call(n.querySelectorAll('[data-bs-dismiss="modal"]')).map(t=>{t.addEventListener("click",()=>{this._isDirty=!1,this._getModal().hide()})}),this.getContainer().getPlugin("form").activateForm(e)}let o=i.querySelector("div.alert");null!==o&&n.querySelector(".modal-body").prepend(o);const s=document.querySelector(e);s.addEventListener("change",()=>{this._isDirty=!0}),s.addEventListener("submit",this._getEventHandler()),this._getModal().show()}_getEventHandler(){return void 0===this.eventHandler&&(this.eventHandler=t=>{const e=t.target;if(void 0!==e.target&&""!==e.target)return!0;const n=document.querySelector(this._getFormIdentifier()+" button[type=submit]");n.textContent=n.textContent+" …",n.disabled=!0;const i=e.dataset.formEvent,r=this.getContainer().getPlugin("event");t.preventDefault(),t.stopPropagation();const o=new Headers;o.append("X-Requested-With","Kimai-Modal");const s={headers:o};this.fetchForm(e,s).then(t=>{t.text().then(t=>{const e=document.createElement("div");e.innerHTML=t;let o=!1,s=!1,a=!1;n.textContent=n.textContent.replace(" …",""),n.disabled=!1;const l=e.querySelector("#form_modal .modal-content");null!==l&&(o=null!==l.querySelector(".is-invalid"),o||(o=null!==l.querySelector(".invalid-feedback")),s=null!==l.querySelector("ul.list-unstyled li.text-danger"),a=null!==e.querySelector("div.alert-danger")),o||s||a?this._openFormInModal(t):(r.trigger(i),this._isDirty=!1,this._getModal().hide())})}).catch(t=>{let i=e.dataset.msgError;null!=i&&""!==i||(i="action.update.error");this.getContainer().getPlugin("alert").error(i,t.message),setTimeout(()=>{n.textContent=n.textContent.replace(" …",""),n.disabled=!1},1500)})}),this.eventHandler}}class k extends s{constructor(){super(),this._selector=".ticktac-menu",this._selectorEmpty=".ticktac-menu-empty",this._favIconUrl=null}getId(){return"active-records"}init(){if(null===document.querySelector(this._selector))return;const t=()=>{this.reloadActiveRecords()};document.addEventListener("kimai.timesheetUpdate",t),document.addEventListener("kimai.timesheetDelete",t),document.addEventListener("kimai.activityUpdate",t),document.addEventListener("kimai.activityDelete",t),document.addEventListener("kimai.projectUpdate",t),document.addEventListener("kimai.projectDelete",t),document.addEventListener("kimai.customerUpdate",t),document.addEventListener("kimai.customerDelete",t),this._updateBrowserTitle=!!this.getConfiguration("updateBrowserTitle");const e=()=>{this._updateDuration()};this._updatesHandler=setInterval(e,1e4),document.addEventListener("kimai.timesheetUpdate",e),document.addEventListener("kimai.reloadedContent",e)}_updateDuration(){const t=document.querySelectorAll('[data-since]:not([data-since=""])');if(this._updateBrowserTitle&&this._changeFavicon(t.length>0),0===t.length)return void(this._updateBrowserTitle&&(void 0===document.body.dataset.title?this._updateBrowserTitle=!1:document.title=document.body.dataset.title));const e=this.getDateUtils();let n=[];for(const i of t){const t=e.formatDuration(i.dataset.since);void 0!==i.dataset.replacer&&null!==i.dataset.title&&"?"!==t&&n.push(t),i.textContent=t}0!==n.length&&this._updateBrowserTitle&&(document.title=n.shift())}_setEntries(t){const e=t.length>0;for(let t of document.querySelectorAll(this._selectorEmpty))t.style.display=e?"none":"inline-block";for(let n of document.querySelectorAll(this._selector)){if(n.style.display=e?"inline-block":"none",!e)for(let t of n.querySelectorAll("[data-since]"))t.dataset.since="";const i=n.querySelector(".ticktac-stop");e?(i&&(i.accesskey="s"),this._replaceInNode(n,t[0])):i&&(i.accesskey=null)}this._updateDuration()}_replaceInNode(t,e){const n=this.getDateUtils(),i=t.querySelectorAll("[data-replacer]");for(let r of i){const i=r.dataset.replacer;"url"===i?r.dataset.href=t.dataset.href.replace("000",e.id):"activity"===i?r.innerText=e.activity.name:"project"===i?r.innerText=e.project.name:"customer"===i?r.innerText=e.project.customer.name:"duration"===i&&(r.dataset.since=e.begin,r.innerText=n.formatDuration(e.duration))}}reloadActiveRecords(){const t=this.getContainer().getPlugin("api"),e=document.querySelector(this._selector).dataset.api;t.get(e,{},t=>{this._setEntries(t)})}_changeFavicon(t){const e=document.createElement("canvas"),n=document.getElementById("favicon");null===this._favIconUrl&&(this._favIconUrl=n.href);const i=n.cloneNode(!0);if(e.getContext&&i){const r=window.devicePixelRatio,o=document.createElement("img");e.height=e.width=16*r,o.onload=function(){const o=e.getContext("2d");if(o.drawImage(this,0,0,e.width,e.height),t){const t=5.5*r;o.fillStyle="rgb(182,57,57)",o.fillRect(e.width/2-t/2,e.height/2-t/2,t,t)}i.href=e.toDataURL("image/png"),n.remove(),document.head.appendChild(i)},o.src=this._favIconUrl}}}class T extends s{getId(){return"event"}trigger(t,e=null){if(""!==t)for(const n of t.split(" ")){let t=new Event(n);null!==e&&(t=new CustomEvent(n,{detail:e})),document.dispatchEvent(t)}}}class E extends s{constructor(t){super(),this._selector=t}init(){document.addEventListener("click",t=>{let e=t.target;for(;null!==e&&"function"==typeof e.matches&&!e.matches("body");){if(e.classList.contains(this._selector)){const n=e.dataset;let i=n.href;i||(i=e.getAttribute("href")),void 0!==n.question?this.getContainer().getPlugin("alert").question(n.question,t=>{t&&this._callApi(i,n)}):this._callApi(i,n),t.preventDefault(),t.stopPropagation()}e=e.parentNode}})}_callApi(t,e){const n=e.method,i=e.event,r=this.getContainer().getPlugin("api"),o=this.getContainer().getPlugin("event"),s=(this.getContainer().getPlugin("alert"),()=>{o.trigger(i),document.dispatchEvent(new CustomEvent("kimai.reloadedContent"))}),a=t=>{let n="action.update.error";void 0!==e.msgError&&(n=e.msgError),document.dispatchEvent(new CustomEvent("kimai.reloadedContent")),r.handleError(n,t)};let l={};if(void 0!==e.payload&&(l=e.payload),document.dispatchEvent(new CustomEvent("kimai.reloadContent")),"PATCH"===n)r.patch(t,l,s,a);else if("POST"===n){let e={};r.post(t,e,s,a)}else"DELETE"===n?r.delete(t,s,a):"GET"===n&&r.get(t,l,s,a)}}class S extends s{getId(){return"alert"}error(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t)),t=t.replace("%reason%",""),void 0===e&&(e=null),null!==e&&(n.has(e)&&(e=n.get(e)),Array.isArray(e)&&(e=e.join("
")));const i="alert_global_error",r=document.getElementById(i);null!==r&&c.aF.getOrCreateInstance(r).hide();const o='\n
\n ";this._showModal(o)}warning(t){this._show("warning",t)}success(t){this._toast("success",t)}info(t){this._show("info",t)}_showModal(t){const e=document.body,n=document.createElement("template");n.innerHTML=t.trim();const i=n.content.firstChild;e.appendChild(i);const r=new c.aF(i);i.addEventListener("hidden.bs.modal",function(){e.removeChild(i)}),r.show()}_show(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));const i='\n \n ";this._showModal(i)}_mapClass(t){return"info"===t||"success"===t||"warning"===t||"danger"===t?t:"error"===t?"danger":"primary"}_toast(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));let i='';"success"===t?i='':"warning"===t?i='':"danger"!==t&&"error"!==t||(i='');const r='',o=document.getElementById("toast-container"),s=document.createElement("template");s.innerHTML=r.trim();const a=s.content.firstChild;o.appendChild(a);const l=new c.y8(a);a.addEventListener("hidden.bs.toast",function(){o.removeChild(a)}),l.show()}question(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t));const i=this._mapClass("info"),r='\n \n ",o=document.body,s=document.createElement("template");s.innerHTML=r.trim();const a=s.content.firstChild;o.appendChild(a),a.querySelector(".question-confirm").addEventListener("click",()=>{e(!0)}),a.querySelector(".question-cancel").addEventListener("click",()=>{e(!1)});const l=new c.aF(a);a.addEventListener("hidden.bs.modal",()=>{o.removeChild(a)}),l.show()}}function x(t,e){t.split(/\s+/).forEach(t=>{e(t)})}class D{constructor(){this._events={}}on(t,e){x(t,t=>{const n=this._events[t]||[];n.push(e),this._events[t]=n})}off(t,e){var n=arguments.length;0!==n?x(t,t=>{if(1===n)return void delete this._events[t];const i=this._events[t];void 0!==i&&(i.splice(i.indexOf(e),1),this._events[t]=i)}):this._events={}}trigger(t,...e){var n=this;x(t,t=>{const i=n._events[t];void 0!==i&&i.forEach(t=>{t.apply(n,e)})})}}const O=t=>(t=t.filter(Boolean)).length<2?t[0]||"":1==I(t)?"["+t.join("")+"]":"(?:"+t.join("|")+")",L=t=>{if(!A(t))return t.join("");let e="",n=0;const i=()=>{n>1&&(e+="{"+n+"}")};return t.forEach((r,o)=>{r!==t[o-1]?(i(),e+=r,n=1):n++}),i(),e},C=t=>{let e=Array.from(t);return O(e)},A=t=>new Set(t).size!==t.length,M=t=>(t+"").replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu,"\\$1"),I=t=>t.reduce((t,e)=>Math.max(t,N(e)),0),N=t=>Array.from(t).length,P=t=>{if(1===t.length)return[[t]];let e=[];const n=t.substring(1);return P(n).forEach(function(n){let i=n.slice(0);i[0]=t.charAt(0)+i[0],e.push(i),i=n.slice(0),i.unshift(t.charAt(0)),e.push(i)}),e},F=[[0,65535]];let j,R;const $={},H={"/":"⁄∕",0:"߀",a:"ⱥɐɑ",aa:"ꜳ",ae:"æǽǣ",ao:"ꜵ",au:"ꜷ",av:"ꜹꜻ",ay:"ꜽ",b:"ƀɓƃ",c:"ꜿƈȼↄ",d:"đɗɖᴅƌꮷԁɦ",e:"ɛǝᴇɇ",f:"ꝼƒ",g:"ǥɠꞡᵹꝿɢ",h:"ħⱨⱶɥ",i:"ɨı",j:"ɉȷ",k:"ƙⱪꝁꝃꝅꞣ",l:"łƚɫⱡꝉꝇꞁɭ",m:"ɱɯϻ",n:"ꞥƞɲꞑᴎлԉ",o:"øǿɔɵꝋꝍᴑ",oe:"œ",oi:"ƣ",oo:"ꝏ",ou:"ȣ",p:"ƥᵽꝑꝓꝕρ",q:"ꝗꝙɋ",r:"ɍɽꝛꞧꞃ",s:"ßȿꞩꞅʂ",t:"ŧƭʈⱦꞇ",th:"þ",tz:"ꜩ",u:"ʉ",v:"ʋꝟʌ",vy:"ꝡ",w:"ⱳ",y:"ƴɏỿ",z:"ƶȥɀⱬꝣ",hv:"ƕ"};for(let t in H){let e=H[t]||"";for(let n=0;nt.normalize(e),z=t=>Array.from(t).reduce((t,e)=>t+B(e),""),B=t=>(t=V(t).toLowerCase().replace(q,t=>$[t]||""),V(t,"NFC"));const W=t=>{const e={},n=(t,n)=>{const i=e[t]||new Set,r=new RegExp("^"+C(i)+"$","iu");n.match(r)||(i.add(M(n)),e[t]=i)};for(let e of function*(t){for(const[e,n]of t)for(let t=e;t<=n;t++){let e=String.fromCharCode(t),n=z(e);n!=e.toLowerCase()&&(n.length>3||0!=n.length&&(yield{folded:n,composed:e,code_point:t}))}}(t))n(e.folded,e.folded),n(e.folded,e.composed);return e},U=t=>{const e=W(t),n={};let i=[];for(let t in e){let r=e[t];r&&(n[t]=C(r)),t.length>1&&i.push(M(t))}i.sort((t,e)=>e.length-t.length);const r=O(i);return R=new RegExp("^"+r,"u"),n},Y=(t,e=1)=>(e=Math.max(e,t.length-1),O(P(t).map(t=>((t,e=1)=>{let n=0;return t=t.map(t=>(j[t]&&(n+=t.length),j[t]||t)),n>=e?L(t):""})(t,e)))),Z=(t,e=!0)=>{let n=t.length>1?1:0;return O(t.map(t=>{let i=[];const r=e?t.length():t.length()-1;for(let e=0;e{for(const n of e){if(n.start!=t.start||n.end!=t.end)continue;if(n.substrs.join("")!==t.substrs.join(""))continue;let e=t.parts;const i=t=>{for(const n of e){if(n.start===t.start&&n.substr===t.substr)return!1;if(1!=t.length&&1!=n.length){if(t.startn.start)return!0;if(n.startt.start)return!0}}return!1};if(!(n.parts.filter(i).length>0))return!0}return!1};class K{parts;substrs;start;end;constructor(){this.parts=[],this.substrs=[],this.start=0,this.end=0}add(t){t&&(this.parts.push(t),this.substrs.push(t.substr),this.start=Math.min(t.start,this.start),this.end=Math.max(t.end,this.end))}last(){return this.parts[this.parts.length-1]}length(){return this.parts.length}clone(t,e){let n=new K,i=JSON.parse(JSON.stringify(this.parts)),r=i.pop();for(const t of i)n.add(t);let o=e.substr.substring(0,t-r.start),s=o.length;return n.add({start:r.start,end:r.start+s,length:s,substr:o}),n}}const J=t=>{var e;void 0===j&&(j=U(e||F)),t=z(t);let n="",i=[new K];for(let e=0;e0){a=a.sort((t,e)=>t.length()-e.length());for(let t of a)G(t,i)||i.push(t)}else if(e>0&&1==l.size&&!l.has("3")){n+=Z(i,!1);let t=new K;const e=i[0];e&&t.add(e.last()),i=[t]}}return n+=Z(i,!0),n},X=(t,e)=>{if(t)return t[e]},Q=(t,e)=>{if(t){for(var n,i=e.split(".");(n=i.shift())&&(t=t[n]););return t}},tt=(t,e,n)=>{var i,r;return t?(t+="",null==e.regex||-1===(r=t.search(e.regex))?0:(i=e.string.length/t.length,0===r&&(i+=.5),i*n)):0},et=(t,e)=>{var n=t[e];if("function"==typeof n)return n;n&&!Array.isArray(n)&&(t[e]=[n])},nt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},it=(t,e)=>"number"==typeof t&&"number"==typeof e?t>e?1:t(e=z(e+"").toLowerCase())?1:e>t?-1:0;class rt{items;settings;constructor(t,e){this.items=t,this.settings=e||{diacritics:!0}}tokenize(t,e,n){if(!t||!t.length)return[];const i=[],r=t.split(/\s+/);var o;return n&&(o=new RegExp("^("+Object.keys(n).map(M).join("|")+"):(.*)$")),r.forEach(t=>{let n,r=null,s=null;o&&(n=t.match(o))&&(r=n[1],t=n[2]),t.length>0&&(s=this.settings.diacritics?J(t)||null:M(t),s&&e&&(s="\\b"+s)),i.push({string:t,regex:s?new RegExp(s,"iu"):null,field:r})}),i}getScoreFunction(t,e){var n=this.prepareSearch(t,e);return this._getScoreFunction(n)}_getScoreFunction(t){const e=t.tokens,n=e.length;if(!n)return function(){return 0};const i=t.options.fields,r=t.weights,o=i.length,s=t.getAttrFn;if(!o)return function(){return 1};const a=1===o?function(t,e){const n=i[0].field;return tt(s(e,n),t,r[n]||1)}:function(t,e){var n=0;if(t.field){const i=s(e,t.field);!t.regex&&i?n+=1/o:n+=tt(i,t,1)}else nt(r,(i,r)=>{n+=tt(s(e,r),t,i)});return n/o};return 1===n?function(t){return a(e[0],t)}:"and"===t.options.conjunction?function(t){var i,r=0;for(let n of e){if((i=a(n,t))<=0)return 0;r+=i}return r/n}:function(t){var i=0;return nt(e,e=>{i+=a(e,t)}),i/n}}getSortFunction(t,e){var n=this.prepareSearch(t,e);return this._getSortFunction(n)}_getSortFunction(t){var e,n=[];const i=this,r=t.options,o=!t.query&&r.sort_empty?r.sort_empty:r.sort;if("function"==typeof o)return o.bind(this);const s=function(e,n){return"$score"===e?n.score:t.getAttrFn(i.items[n.id],e)};if(o)for(let e of o)(t.query||"$score"!==e.field)&&n.push(e);if(t.query){e=!0;for(let t of n)if("$score"===t.field){e=!1;break}e&&n.unshift({field:"$score",direction:"desc"})}else n=n.filter(t=>"$score"!==t.field);return n.length?function(t,e){var i,r;for(let o of n){if(r=o.field,i=("desc"===o.direction?-1:1)*it(s(r,t),s(r,e)))return i}return 0}:null}prepareSearch(t,e){const n={};var i=Object.assign({},e);if(et(i,"sort"),et(i,"sort_empty"),i.fields){et(i,"fields");const t=[];i.fields.forEach(e=>{"string"==typeof e&&(e={field:e,weight:1}),t.push(e),n[e.field]="weight"in e?e.weight:1}),i.fields=t}return{options:i,query:t.toLowerCase().trim(),tokens:this.tokenize(t,i.respect_word_boundaries,n),total:0,items:[],weights:n,getAttrFn:i.nesting?Q:X}}search(t,e){var n,i,r=this;i=this.prepareSearch(t,e),e=i.options,t=i.query;const o=e.score||r._getScoreFunction(i);t.length?nt(r.items,(t,r)=>{n=o(t),(!1===e.filter||n>0)&&i.items.push({score:n,id:r})}):nt(r.items,(t,e)=>{i.items.push({score:1,id:e})});const s=r._getSortFunction(i);return s&&i.items.sort(s),i.total=i.items.length,"number"==typeof e.limit&&(i.items=i.items.slice(0,e.limit)),i}}const ot=t=>null==t?null:st(t),st=t=>"boolean"==typeof t?t?"1":"0":t+"",at=t=>(t+"").replace(/&/g,"&").replace(//g,">").replace(/"/g,"""),lt=(t,e)=>{var n;return function(i,r){var o=this;n&&(o.loading=Math.max(o.loading-1,0),clearTimeout(n)),n=setTimeout(function(){n=null,o.loadedSearches[i]=!0,t.call(o,i,r)},e)}},ct=(t,e,n)=>{var i,r=t.trigger,o={};for(i of(t.trigger=function(){var n=arguments[0];if(-1===e.indexOf(n))return r.apply(t,arguments);o[n]=arguments},n.apply(t,[]),t.trigger=r,e))i in o&&r.apply(t,o[i])},ut=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},dt=(t,e,n,i)=>{t.addEventListener(e,n,i)},ht=(t,e)=>!!e&&(!!e[t]&&1===(e.altKey?1:0)+(e.ctrlKey?1:0)+(e.shiftKey?1:0)+(e.metaKey?1:0)),pt=(t,e)=>{const n=t.getAttribute("id");return n||(t.setAttribute("id",e),e)},mt=t=>t.replace(/[\\"']/g,"\\$&"),ft=(t,e)=>{e&&t.append(e)},gt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},vt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},yt=t=>"string"==typeof t&&t.indexOf("<")>-1,bt=(t,e)=>{var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!1),t.dispatchEvent(n)},_t=(t,e)=>{Object.assign(t.style,e)},wt=(t,...e)=>{var n=Tt(e);(t=Et(t)).map(t=>{n.map(e=>{t.classList.add(e)})})},kt=(t,...e)=>{var n=Tt(e);(t=Et(t)).map(t=>{n.map(e=>{t.classList.remove(e)})})},Tt=t=>{var e=[];return gt(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Et=t=>(Array.isArray(t)||(t=[t]),t),St=(t,e,n)=>{if(!n||n.contains(t))for(;t&&t.matches;){if(t.matches(e))return t;t=t.parentNode}},xt=(t,e=0)=>e>0?t[t.length-1]:t[0],Dt=(t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n},Ot=(t,e)=>{gt(e,(e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)})},Lt=(t,e)=>{t.parentNode&&t.parentNode.replaceChild(e,t)},Ct=(t,e)=>{if(null===e)return;if("string"==typeof e){if(!e.length)return;e=new RegExp(e,"i")}const n=t=>3===t.nodeType?(t=>{var n=t.data.match(e);if(n&&t.data.length>0){var i=document.createElement("span");i.className="highlight";var r=t.splitText(n.index);r.splitText(n[0].length);var o=r.cloneNode(!0);return i.appendChild(o),Lt(r,i),1}return 0})(t):((t=>{1!==t.nodeType||!t.childNodes||/(script|style)/i.test(t.tagName)||"highlight"===t.className&&"SPAN"===t.tagName||Array.from(t.childNodes).forEach(t=>{n(t)})})(t),0);n(t)},At="undefined"!=typeof navigator&&/Mac/.test(navigator.userAgent)?"metaKey":"ctrlKey";var Mt={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:null,createOnBlur:!1,createFilter:null,clearAfterSelect:!1,highlight:!0,openOnFocus:!0,shouldOpen:null,maxOptions:50,maxItems:null,hideSelected:null,duplicates:!1,addPrecedence:!1,selectOnTab:!1,preload:null,allowEmptyOption:!1,refreshThrottle:300,loadThrottle:300,loadingClass:"loading",dataAttr:null,optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"ts-wrapper",controlClass:"ts-control",dropdownClass:"ts-dropdown",dropdownContentClass:"ts-dropdown-content",itemClass:"item",optionClass:"option",dropdownParent:null,controlInput:'',copyClassesToDropdown:!1,placeholder:null,hidePlaceholder:null,shouldLoad:function(t){return t.length>0},render:{}};function It(t,e){var n=Object.assign({},Mt,e),i=n.dataAttr,r=n.labelField,o=n.valueField,s=n.disabledField,a=n.optgroupField,l=n.optgroupLabelField,c=n.optgroupValueField,u=t.tagName.toLowerCase(),d=t.getAttribute("placeholder")||t.getAttribute("data-placeholder");if(!d&&!n.allowEmptyOption){let e=t.querySelector('option[value=""]');e&&(d=e.textContent)}var h={placeholder:d,options:[],optgroups:[],items:[],maxItems:null};return"select"===u?(()=>{var e,u=h.options,d={},p=1;let m=0;var f=t=>{var e=Object.assign({},t.dataset),n=i&&e[i];return"string"==typeof n&&n.length&&(e=Object.assign(e,JSON.parse(n))),e},g=(t,e)=>{var i=ot(t.value);if(null!=i&&(i||n.allowEmptyOption)){if(d.hasOwnProperty(i)){if(e){var l=d[i][a];l?Array.isArray(l)?l.push(e):d[i][a]=[l,e]:d[i][a]=e}}else{var c=f(t);c[r]=c[r]||t.textContent,c[o]=c[o]||i,c[s]=c[s]||t.disabled,c[a]=c[a]||e,c.$option=t,c.$order=c.$order||++m,d[i]=c,u.push(c)}t.selected&&h.items.push(i)}};h.maxItems=t.hasAttribute("multiple")?null:1,gt(t.children,t=>{var n,i,r;"optgroup"===(e=t.tagName.toLowerCase())?((r=f(n=t))[l]=r[l]||n.getAttribute("label")||"",r[c]=r[c]||p++,r[s]=r[s]||n.disabled,r.$order=r.$order||++m,h.optgroups.push(r),i=r[c],gt(n.children,t=>{g(t,i)})):"option"===e&&g(t)})})():(()=>{const e=t.getAttribute(i);if(e)h.options=JSON.parse(e),gt(h.options,t=>{h.items.push(t[o])});else{var s=t.value.trim()||"";if(!n.allowEmptyOption&&!s.length)return;const e=s.split(n.delimiter);gt(e,t=>{const e={};e[r]=t,e[o]=t,h.options.push(e)}),h.items=e}})(),Object.assign({},Mt,h,e)}var Nt=0;class Pt extends(function(t){return t.plugins={},class extends t{constructor(){super(...arguments),this.plugins={names:[],settings:{},requested:{},loaded:{}}}static define(e,n){t.plugins[e]={name:e,fn:n}}initializePlugins(t){var e,n;const i=this,r=[];if(Array.isArray(t))t.forEach(t=>{"string"==typeof t?r.push(t):(i.plugins.settings[t.name]=t.options,r.push(t.name))});else if(t)for(e in t)t.hasOwnProperty(e)&&(i.plugins.settings[e]=t[e],r.push(e));for(;n=r.shift();)i.require(n)}loadPlugin(e){var n=this,i=n.plugins,r=t.plugins[e];if(!t.plugins.hasOwnProperty(e))throw new Error('Unable to find "'+e+'" plugin');i.requested[e]=!0,i.loaded[e]=r.fn.apply(n,[n.plugins.settings[e]||{}]),i.names.push(e)}require(t){var e=this,n=e.plugins;if(!e.plugins.loaded.hasOwnProperty(t)){if(n.requested[t])throw new Error('Plugin has circular dependency ("'+t+'")');e.loadPlugin(t)}return n.loaded[t]}}}(D)){constructor(t,e){var n;super(),this.order=0,this.isOpen=!1,this.isDisabled=!1,this.isReadOnly=!1,this.isInvalid=!1,this.isValid=!0,this.isLocked=!1,this.isFocused=!1,this.isInputHidden=!1,this.isSetup=!1,this.ignoreFocus=!1,this.ignoreHover=!1,this.hasOptions=!1,this.lastValue="",this.caretPos=0,this.loading=0,this.loadedSearches={},this.activeOption=null,this.activeItems=[],this.optgroups={},this.options={},this.userOptions={},this.items=[],this.refreshTimeout=null,Nt++;var i=vt(t);if(i.tomselect)throw new Error("Tom Select already initialized on this element");i.tomselect=this,n=(window.getComputedStyle&&window.getComputedStyle(i,null)).getPropertyValue("direction");const r=It(i,e);this.settings=r,this.input=i,this.tabIndex=i.tabIndex||0,this.is_select_tag="select"===i.tagName.toLowerCase(),this.rtl=/rtl/i.test(n),this.inputId=pt(i,"tomselect-"+Nt),this.isRequired=i.required,this.sifter=new rt(this.options,{diacritics:r.diacritics}),r.mode=r.mode||(1===r.maxItems?"single":"multi"),"boolean"!=typeof r.hideSelected&&(r.hideSelected="multi"===r.mode),"boolean"!=typeof r.hidePlaceholder&&(r.hidePlaceholder="multi"!==r.mode);var o=r.createFilter;"function"!=typeof o&&("string"==typeof o&&(o=new RegExp(o)),o instanceof RegExp?r.createFilter=t=>o.test(t):r.createFilter=t=>this.settings.duplicates||!this.options[t]),this.initializePlugins(r.plugins),this.setupCallbacks(),this.setupTemplates();const s=vt("
"),a=vt("
"),l=this._render("dropdown"),c=vt('
'),u=this.input.getAttribute("class")||"",d=r.mode;var h;if(wt(s,r.wrapperClass,u,d),wt(a,r.controlClass),ft(s,a),wt(l,r.dropdownClass,d),r.copyClassesToDropdown&&wt(l,u),wt(c,r.dropdownContentClass),ft(l,c),vt(r.dropdownParent||s).appendChild(l),yt(r.controlInput)){h=vt(r.controlInput);gt(["autocorrect","autocapitalize","autocomplete","spellcheck","aria-label"],t=>{i.getAttribute(t)&&Ot(h,{[t]:i.getAttribute(t)})}),h.tabIndex=-1,a.appendChild(h),this.focus_node=h}else r.controlInput?(h=vt(r.controlInput),this.focus_node=h):(h=vt(""),this.focus_node=a);this.wrapper=s,this.dropdown=l,this.dropdown_content=c,this.control=a,this.control_input=h,this.setup()}setup(){const t=this,e=t.settings,n=t.control_input,i=t.dropdown,r=t.dropdown_content,o=t.wrapper,s=t.control,a=t.input,l=t.focus_node,c={passive:!0},u=t.inputId+"-ts-dropdown";Ot(r,{id:u}),Ot(l,{role:"combobox","aria-haspopup":"listbox","aria-expanded":"false","aria-controls":u});const d=pt(l,t.inputId+"-ts-control"),h="label[for='"+(t=>t.replace(/['"\\]/g,"\\$&"))(t.inputId)+"']",p=document.querySelector(h),m=t.focus.bind(t);if(p){dt(p,"click",m),Ot(p,{for:d});const e=pt(p,t.inputId+"-ts-label");Ot(l,{"aria-labelledby":e}),Ot(r,{"aria-labelledby":e})}if(o.style.width=a.style.width,o.style.minWidth=a.style.minWidth,o.style.maxWidth=a.style.maxWidth,t.plugins.names.length){const e="plugin-"+t.plugins.names.join(" plugin-");wt([o,i],e)}(null===e.maxItems||e.maxItems>1)&&t.is_select_tag&&Ot(a,{multiple:"multiple"}),e.placeholder&&Ot(n,{placeholder:e.placeholder}),!e.splitOn&&e.delimiter&&(e.splitOn=new RegExp("\\s*"+M(e.delimiter)+"+\\s*")),e.load&&e.loadThrottle&&(e.load=lt(e.load,e.loadThrottle)),dt(i,"mousemove",()=>{t.ignoreHover=!1}),dt(i,"mouseenter",e=>{var n=St(e.target,"[data-selectable]",i);n&&t.onOptionHover(e,n)},{capture:!0}),dt(i,"click",e=>{const n=St(e.target,"[data-selectable]");n&&(t.onOptionSelect(e,n),ut(e,!0))}),dt(s,"click",e=>{var i=St(e.target,"[data-ts-item]",s);i&&t.onItemSelect(e,i)?ut(e,!0):""==n.value&&(t.onClick(),ut(e,!0))}),dt(l,"keydown",e=>t.onKeyDown(e)),dt(n,"keypress",e=>t.onKeyPress(e)),dt(n,"input",e=>t.onInput(e)),dt(l,"blur",e=>t.onBlur(e)),dt(l,"focus",e=>t.onFocus(e)),dt(n,"paste",e=>t.onPaste(e));const f=e=>{const r=e.composedPath()[0];if(!o.contains(r)&&!i.contains(r))return t.isFocused&&t.blur(),void t.inputState();r==n&&t.isOpen?e.stopPropagation():ut(e,!0)},g=()=>{t.isOpen&&t.positionDropdown()},v=()=>{t.isValid&&(t.isValid=!1,t.isInvalid=!0,t.refreshState())};dt(a,"invalid",v),dt(document,"mousedown",f),dt(window,"scroll",g,c),dt(window,"resize",g,c),this._destroy=()=>{a.removeEventListener("invalid",v),document.removeEventListener("mousedown",f),window.removeEventListener("scroll",g),window.removeEventListener("resize",g),p&&p.removeEventListener("click",m)},this.revertSettings={innerHTML:a.innerHTML,tabIndex:a.tabIndex},a.tabIndex=-1,a.insertAdjacentElement("afterend",t.wrapper),t.sync(!1),e.items=[],delete e.optgroups,delete e.options,t.refreshItems(),t.close(!1),t.inputState(),t.isSetup=!0,a.disabled?t.disable():a.readOnly?t.setReadOnly(!0):t.enable(),t.on("change",this.onChange),wt(a,"tomselected","ts-hidden-accessible"),t.trigger("initialize"),!0===e.preload&&t.preload()}setupOptions(t=[],e=[]){this.addOptions(t),gt(e,t=>{this.registerOptionGroup(t)})}setupTemplates(){var t=this,e=t.settings.labelField,n=t.settings.optgroupLabelField,i={optgroup:t=>{let e=document.createElement("div");return e.className="optgroup",e.appendChild(t.options),e},optgroup_header:(t,e)=>'
'+e(t[n])+"
",option:(t,n)=>"
"+n(t[e])+"
",item:(t,n)=>"
"+n(t[e])+"
",option_create:(t,e)=>'
Add '+e(t.input)+"
",no_results:()=>'
No results found
',loading:()=>'
',not_loading:()=>{},dropdown:()=>"
"};t.settings.render=Object.assign({},i,t.settings.render)}setupCallbacks(){var t,e,n={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",item_select:"onItemSelect",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(t in n)(e=this.settings[n[t]])&&this.on(t,e)}sync(t=!0){const e=this,n=t?It(e.input,{delimiter:e.settings.delimiter,allowEmptyOption:e.settings.allowEmptyOption}):e.settings;e.setupOptions(n.options,n.optgroups),e.setValue(n.items||[],!0),e.lastQuery=null}onClick(){var t=this;if(t.activeItems.length>0)return t.clearActiveItems(),void t.focus();t.isFocused&&t.isOpen?t.blur():t.focus()}onMouseDown(){}onChange(){bt(this.input,"input"),bt(this.input,"change")}onPaste(t){var e=this;e.isInputHidden||e.isLocked?ut(t):e.settings.splitOn&&setTimeout(()=>{var t=e.inputValue();if(t.match(e.settings.splitOn)){var n=t.trim().split(e.settings.splitOn);gt(n,t=>{ot(t)&&(this.options[t]?e.addItem(t):e.createItem(t))})}},0)}onKeyPress(t){var e=this;if(!e.isLocked){var n=String.fromCharCode(t.keyCode||t.which);return e.settings.create&&"multi"===e.settings.mode&&n===e.settings.delimiter?(e.createItem(),void ut(t)):void 0}ut(t)}onKeyDown(t){var e=this;if(e.ignoreHover=!0,e.isLocked)9!==t.keyCode&&ut(t);else{switch(t.keyCode){case 65:if(ht(At,t)&&""==e.control_input.value)return ut(t),void e.selectAll();break;case 27:return e.isOpen&&(ut(t,!0),e.close()),void e.clearActiveItems();case 40:if(!e.isOpen&&e.hasOptions)e.open();else if(e.activeOption){let t=e.getAdjacent(e.activeOption,1);t&&e.setActiveOption(t)}return void ut(t);case 38:if(e.activeOption){let t=e.getAdjacent(e.activeOption,-1);t&&e.setActiveOption(t)}return void ut(t);case 13:return void(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):(e.settings.create&&e.createItem()||document.activeElement==e.control_input&&e.isOpen)&&ut(t));case 37:return void e.advanceSelection(-1,t);case 39:return void e.advanceSelection(1,t);case 9:return void(e.settings.selectOnTab&&(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):e.settings.create&&e.createItem()&&ut(t)));case 8:case 46:return void e.deleteSelection(t)}e.isInputHidden&&!ht(At,t)&&ut(t)}}onInput(t){if(this.isLocked)return;const e=this.inputValue();this.lastValue!==e&&(this.lastValue=e,""!=e?(this.refreshTimeout&&window.clearTimeout(this.refreshTimeout),this.refreshTimeout=((t,e)=>e>0?window.setTimeout(t,e):(t.call(null),null))(()=>{this.refreshTimeout=null,this._onInput()},this.settings.refreshThrottle)):this._onInput())}_onInput(){const t=this.lastValue;this.settings.shouldLoad.call(this,t)&&this.load(t),this.refreshOptions(),this.trigger("type",t)}onOptionHover(t,e){this.ignoreHover||this.setActiveOption(e,!1)}onFocus(t){var e=this,n=e.isFocused;if(e.isDisabled||e.isReadOnly)return e.blur(),void ut(t);e.ignoreFocus||(e.isFocused=!0,"focus"===e.settings.preload&&e.preload(),n||e.trigger("focus"),e.activeItems.length||(e.inputState(),e.refreshOptions(!!e.settings.openOnFocus)),e.refreshState())}onBlur(t){if(!1!==document.hasFocus()){var e=this;if(e.isFocused){e.isFocused=!1,e.ignoreFocus=!1;var n=()=>{e.close(),e.setActiveItem(),e.setCaret(e.items.length),e.trigger("blur")};e.settings.create&&e.settings.createOnBlur?e.createItem(null,n):n()}}}onOptionSelect(t,e){var n,i=this;e.parentElement&&e.parentElement.matches("[data-disabled]")||(e.classList.contains("create")?i.createItem(null,()=>{i.settings.closeAfterSelect?i.close():i.settings.clearAfterSelect&&i.setTextboxValue()}):void 0!==(n=e.dataset.value)&&(i.lastQuery=null,i.addItem(n),i.settings.closeAfterSelect?i.close():i.settings.clearAfterSelect&&i.setTextboxValue(),!i.settings.hideSelected&&t.type&&/click/.test(t.type)&&i.setActiveOption(e)))}canSelect(t){return!!(this.isOpen&&t&&this.dropdown_content.contains(t))}onItemSelect(t,e){var n=this;return!n.isLocked&&"multi"===n.settings.mode&&(ut(t),n.setActiveItem(e,t),!0)}canLoad(t){return!!this.settings.load&&!this.loadedSearches.hasOwnProperty(t)}load(t){const e=this;if(!e.canLoad(t))return;wt(e.wrapper,e.settings.loadingClass),e.loading++;const n=e.loadCallback.bind(e);e.settings.load.call(e,t,n)}loadCallback(t,e){const n=this;n.loading=Math.max(n.loading-1,0),n.lastQuery=null,n.clearActiveOption(),n.setupOptions(t,e),n.refreshOptions(n.isFocused&&!n.isInputHidden),n.loading||kt(n.wrapper,n.settings.loadingClass),n.trigger("load",t,e)}preload(){var t=this.wrapper.classList;t.contains("preloaded")||(t.add("preloaded"),this.load(""))}setTextboxValue(t=""){var e=this.control_input;e.value!==t&&(e.value=t,bt(e,"update"),this.lastValue=t)}getValue(){return this.is_select_tag&&this.input.hasAttribute("multiple")?this.items:this.items.join(this.settings.delimiter)}setValue(t,e){ct(this,e?[]:["change"],()=>{this.clear(e),this.addItems(t,e)})}setMaxItems(t){0===t&&(t=null),this.settings.maxItems=t,this.refreshState()}setActiveItem(t,e){var n,i,r,o,s,a,l=this;if("single"!==l.settings.mode){if(!t)return l.clearActiveItems(),void(l.isFocused&&l.inputState());if("click"===(n=e&&e.type.toLowerCase())&&ht("shiftKey",e)&&l.activeItems.length){for(a=l.getLastActive(),(r=Array.prototype.indexOf.call(l.control.children,a))>(o=Array.prototype.indexOf.call(l.control.children,t))&&(s=r,r=o,o=s),i=r;i<=o;i++)t=l.control.children[i],-1===l.activeItems.indexOf(t)&&l.setActiveItemClass(t);ut(e)}else"click"===n&&ht(At,e)||"keydown"===n&&ht("shiftKey",e)?t.classList.contains("active")?l.removeActiveItem(t):l.setActiveItemClass(t):(l.clearActiveItems(),l.setActiveItemClass(t));l.inputState(),l.isFocused||l.focus()}}setActiveItemClass(t){const e=this,n=e.control.querySelector(".last-active");n&&kt(n,"last-active"),wt(t,"active last-active"),e.trigger("item_select",t),-1==e.activeItems.indexOf(t)&&e.activeItems.push(t)}removeActiveItem(t){var e=this.activeItems.indexOf(t);this.activeItems.splice(e,1),kt(t,"active")}clearActiveItems(){kt(this.activeItems,"active"),this.activeItems=[]}setActiveOption(t,e=!0){t!==this.activeOption&&(this.clearActiveOption(),t&&(this.activeOption=t,Ot(this.focus_node,{"aria-activedescendant":t.getAttribute("id")}),Ot(t,{"aria-selected":"true"}),wt(t,"active"),e&&this.scrollToOption(t)))}scrollToOption(t,e){if(!t)return;const n=this.dropdown_content,i=n.clientHeight,r=n.scrollTop||0,o=t.offsetHeight,s=t.getBoundingClientRect().top-n.getBoundingClientRect().top+r;s+o>i+r?this.scroll(s-i+o,e):s{t.setActiveItemClass(e)}))}inputState(){var t=this;t.control.contains(t.control_input)&&(Ot(t.control_input,{placeholder:t.settings.placeholder}),t.activeItems.length>0||!t.isFocused&&t.settings.hidePlaceholder&&t.items.length>0?(t.setTextboxValue(),t.isInputHidden=!0):(t.settings.hidePlaceholder&&t.items.length>0&&Ot(t.control_input,{placeholder:""}),t.isInputHidden=!1),t.wrapper.classList.toggle("input-hidden",t.isInputHidden))}inputValue(){return this.control_input.value.trim()}focus(){var t=this;t.isDisabled||t.isReadOnly||(t.ignoreFocus=!0,t.control_input.offsetWidth?t.control_input.focus():t.focus_node.focus(),setTimeout(()=>{t.ignoreFocus=!1,t.onFocus()},0))}blur(){this.focus_node.blur(),this.onBlur()}getScoreFunction(t){return this.sifter.getScoreFunction(t,this.getSearchOptions())}getSearchOptions(){var t=this.settings,e=t.sortField;return"string"==typeof t.sortField&&(e=[{field:t.sortField}]),{fields:t.searchField,conjunction:t.searchConjunction,sort:e,nesting:t.nesting}}search(t){var e,n,i=this,r=this.getSearchOptions();if(i.settings.score&&"function"!=typeof(n=i.settings.score.call(i,t)))throw new Error('Tom Select "score" setting must be a function that returns a function');return t!==i.lastQuery?(i.lastQuery=t,/(.)\1{15,}/.test(t)&&(t=""),e=i.sifter.search(t,Object.assign(r,{score:n})),i.currentResults=e):e=Object.assign({},i.currentResults),i.settings.hideSelected&&(e.items=e.items.filter(t=>{let e=ot(t.id);return!(null!==e&&-1!==i.items.indexOf(e))})),e}refreshOptions(t=!0){var e,n,i,r,o,s,a,l,c,u;const d={},h=[];var p=this,m=p.inputValue();const f=m===p.lastQuery||""==m&&null==p.lastQuery;var g=p.search(m),v=null,y=p.settings.shouldOpen||!1,b=p.dropdown_content;f&&(v=p.activeOption)&&(c=v.closest("[data-group]")),r=g.items.length,"number"==typeof p.settings.maxOptions&&(r=Math.min(r,p.settings.maxOptions)),r>0&&(y=!0);const _=(t,e)=>{let n=d[t];if(void 0!==n){let t=h[n];if(void 0!==t)return[n,t.fragment]}let i=document.createDocumentFragment();return n=h.length,h.push({fragment:i,order:e,optgroup:t}),[n,i]};for(e=0;e0&&(u=u.cloneNode(!0),Ot(u,{id:a.$id+"-clone-"+n,"aria-selected":null}),u.classList.add("ts-cloned"),kt(u,"active"),p.activeOption&&p.activeOption.dataset.value==r&&c&&c.dataset.group===o.toString()&&(v=u)),l.appendChild(u),""!=o&&(d[o]=i)}}var k;p.settings.lockOptgroupOrder&&h.sort((t,e)=>t.order-e.order),a=document.createDocumentFragment(),gt(h,t=>{let e=t.fragment,n=t.optgroup;if(!e||!e.children.length)return;let i=p.optgroups[n];if(void 0!==i){let t=document.createDocumentFragment(),n=p.render("optgroup_header",i);ft(t,n),ft(t,e);let r=p.render("optgroup",{group:i,options:t});ft(a,r)}else ft(a,e)}),b.innerHTML="",ft(b,a),p.settings.highlight&&(k=b.querySelectorAll("span.highlight"),Array.prototype.forEach.call(k,function(t){var e=t.parentNode;e.replaceChild(t.firstChild,t),e.normalize()}),g.query.length&&g.tokens.length&>(g.tokens,t=>{Ct(b,t.regex)}));var T=t=>{let e=p.render(t,{input:m});return e&&(y=!0,b.insertBefore(e,b.firstChild)),e};if(p.loading?T("loading"):p.settings.shouldLoad.call(p,m)?0===g.items.length&&T("no_results"):T("not_loading"),(l=p.canCreate(m))&&(u=T("option_create")),p.hasOptions=g.items.length>0||l,y){if(g.items.length>0){if(v||"single"!==p.settings.mode||null==p.items[0]||(v=p.getOption(p.items[0])),!b.contains(v)){let t=0;u&&!p.settings.addPrecedence&&(t=1),v=p.selectable()[t]}}else u&&(v=u);t&&!p.isOpen&&(p.open(),p.scrollToOption(v,"auto")),p.setActiveOption(v)}else p.clearActiveOption(),t&&p.isOpen&&p.close(!1)}selectable(){return this.dropdown_content.querySelectorAll("[data-selectable]")}addOption(t,e=!1){const n=this;if(Array.isArray(t))return n.addOptions(t,e),!1;const i=ot(t[n.settings.valueField]);return null!==i&&!n.options.hasOwnProperty(i)&&(t.$order=t.$order||++n.order,t.$id=n.inputId+"-opt-"+t.$order,n.options[i]=t,n.lastQuery=null,e&&(n.userOptions[i]=e,n.trigger("option_add",i,t)),i)}addOptions(t,e=!1){gt(t,t=>{this.addOption(t,e)})}registerOption(t){return this.addOption(t)}registerOptionGroup(t){var e=ot(t[this.settings.optgroupValueField]);return null!==e&&(t.$order=t.$order||++this.order,this.optgroups[e]=t,e)}addOptionGroup(t,e){var n;e[this.settings.optgroupValueField]=t,(n=this.registerOptionGroup(e))&&this.trigger("optgroup_add",n,e)}removeOptionGroup(t){this.optgroups.hasOwnProperty(t)&&(delete this.optgroups[t],this.clearCache(),this.trigger("optgroup_remove",t))}clearOptionGroups(){this.optgroups={},this.clearCache(),this.trigger("optgroup_clear")}updateOption(t,e){const n=this;var i,r;const o=ot(t),s=ot(e[n.settings.valueField]);if(null===o)return;const a=n.options[o];if(null==a)return;if("string"!=typeof s)throw new Error("Value must be set in option data");const l=n.getOption(o),c=n.getItem(o);if(e.$order=e.$order||a.$order,delete n.options[o],n.uncacheValue(s),n.options[s]=e,l){if(n.dropdown_content.contains(l)){const t=n._render("option",e);Lt(l,t),n.activeOption===l&&n.setActiveOption(t)}l.remove()}c&&(-1!==(r=n.items.indexOf(o))&&n.items.splice(r,1,s),i=n._render("item",e),c.classList.contains("active")&&wt(i,"active"),Lt(c,i)),n.lastQuery=null}removeOption(t,e){const n=this;t=st(t),n.uncacheValue(t),delete n.userOptions[t],delete n.options[t],n.lastQuery=null,n.trigger("option_remove",t),n.removeItem(t,e)}clearOptions(t){const e=(t||this.clearFilter).bind(this);this.loadedSearches={},this.userOptions={},this.clearCache();const n={};gt(this.options,(t,i)=>{e(t,i)&&(n[i]=t)}),this.options=this.sifter.items=n,this.lastQuery=null,this.trigger("option_clear")}clearFilter(t,e){return this.items.indexOf(e)>=0}getOption(t,e=!1){const n=ot(t);if(null===n)return null;const i=this.options[n];if(null!=i){if(i.$div)return i.$div;if(e)return this._render("option",i)}return null}getAdjacent(t,e,n="option"){var i;if(!t)return null;i="item"==n?this.controlChildren():this.dropdown_content.querySelectorAll("[data-selectable]");for(let n=0;n0?i[n+1]:i[n-1];return null}getItem(t){if("object"==typeof t)return t;var e=ot(t);return null!==e?this.control.querySelector(`[data-value="${mt(e)}"]`):null}addItems(t,e){var n=this,i=Array.isArray(t)?t:[t];const r=(i=i.filter(t=>-1===n.items.indexOf(t)))[i.length-1];i.forEach(t=>{n.isPending=t!==r,n.addItem(t,e)})}addItem(t,e){ct(this,e?[]:["change","dropdown_close"],()=>{var n,i;const r=this,o=r.settings.mode,s=ot(t);if((!s||-1===r.items.indexOf(s)||("single"===o&&r.close(),"single"!==o&&r.settings.duplicates))&&null!==s&&r.options.hasOwnProperty(s)&&("single"===o&&r.clear(e),"multi"!==o||!r.isFull())){if(n=r._render("item",r.options[s]),r.control.contains(n)&&(n=n.cloneNode(!0)),i=r.isFull(),r.items.splice(r.caretPos,0,s),r.insertAtCaret(n),r.isSetup){if(!r.isPending&&r.settings.hideSelected){let t=r.getOption(s),e=r.getAdjacent(t,1);e&&r.setActiveOption(e)}r.settings.clearAfterSelect&&r.setTextboxValue(),r.isPending||r.settings.closeAfterSelect||r.refreshOptions(r.isFocused&&"single"!==o),0!=r.settings.closeAfterSelect&&r.isFull()?r.close():r.isPending||r.positionDropdown(),r.trigger("item_add",s,n),r.isPending||r.updateOriginalInput({silent:e})}(!r.isPending||!i&&r.isFull())&&(r.inputState(),r.refreshState())}})}removeItem(t=null,e){const n=this;if(!(t=n.getItem(t)))return;var i,r;const o=t.dataset.value;i=Dt(t),t.remove(),t.classList.contains("active")&&(r=n.activeItems.indexOf(t),n.activeItems.splice(r,1),kt(t,"active")),n.items.splice(i,1),n.lastQuery=null,!n.settings.persist&&n.userOptions.hasOwnProperty(o)&&n.removeOption(o,e),i{}){3===arguments.length&&(e=arguments[2]),"function"!=typeof e&&(e=()=>{});var n,i=this,r=i.caretPos;if(t=t||i.inputValue(),!i.canCreate(t)){return ot(t)&&this.options[t]&&i.addItem(t),e(),!1}i.lock();var o=!1,s=t=>{if(i.unlock(),!t||"object"!=typeof t)return e();var n=ot(t[i.settings.valueField]);if("string"!=typeof n)return e();i.setTextboxValue(),i.addOption(t,!0),i.setCaret(r),i.addItem(n),e(t),o=!0};return n="function"==typeof i.settings.create?i.settings.create.call(this,t,s):{[i.settings.labelField]:t,[i.settings.valueField]:t},o||s(n),!0}refreshItems(){var t=this;t.lastQuery=null,t.isSetup&&t.addItems(t.items),t.updateOriginalInput(),t.refreshState()}refreshState(){const t=this;t.refreshValidityState();const e=t.isFull(),n=t.isLocked;t.wrapper.classList.toggle("rtl",t.rtl);const i=t.wrapper.classList;var r;i.toggle("focus",t.isFocused),i.toggle("disabled",t.isDisabled),i.toggle("readonly",t.isReadOnly),i.toggle("required",t.isRequired),i.toggle("invalid",!t.isValid),i.toggle("locked",n),i.toggle("full",e),i.toggle("input-active",t.isFocused&&!t.isInputHidden),i.toggle("dropdown-active",t.isOpen),i.toggle("has-options",(r=t.options,0===Object.keys(r).length)),i.toggle("has-items",t.items.length>0)}refreshValidityState(){var t=this;t.input.validity&&(t.isValid=t.input.validity.valid,t.isInvalid=!t.isValid)}isFull(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems}updateOriginalInput(t={}){const e=this;var n,i;const r=e.input.querySelector('option[value=""]');if(e.is_select_tag){const o=[],s=e.input.querySelectorAll("option:checked").length;function a(t,n,i){return t||(t=vt('")),t!=r&&e.input.append(t),o.push(t),(t!=r||s>0)&&(t.selected=!0),t}e.input.querySelectorAll("option:checked").forEach(t=>{t.selected=!1}),0==e.items.length&&"single"==e.settings.mode?a(r,"",""):e.items.forEach(t=>{if(n=e.options[t],i=n[e.settings.labelField]||"",o.includes(n.$option)){a(e.input.querySelector(`option[value="${mt(t)}"]:not(:checked)`),t,i)}else n.$option=a(n.$option,t,i)})}else e.input.value=e.getValue();e.isSetup&&(t.silent||e.trigger("change",e.getValue()))}open(){var t=this;t.isLocked||t.isOpen||"multi"===t.settings.mode&&t.isFull()||(t.isOpen=!0,Ot(t.focus_node,{"aria-expanded":"true"}),t.refreshState(),_t(t.dropdown,{visibility:"hidden",display:"block"}),t.positionDropdown(),_t(t.dropdown,{visibility:"visible",display:"block"}),t.focus(),t.trigger("dropdown_open",t.dropdown))}close(t=!0){var e=this,n=e.isOpen;t&&(e.setTextboxValue(),"single"===e.settings.mode&&e.items.length&&e.inputState()),e.isOpen=!1,Ot(e.focus_node,{"aria-expanded":"false"}),_t(e.dropdown,{display:"none"}),e.settings.hideSelected&&e.clearActiveOption(),e.refreshState(),n&&e.trigger("dropdown_close",e.dropdown)}positionDropdown(){if("body"===this.settings.dropdownParent){var t=this.control,e=t.getBoundingClientRect(),n=t.offsetHeight+e.top+window.scrollY,i=e.left+window.scrollX;_t(this.dropdown,{width:e.width+"px",top:n+"px",left:i+"px"})}}clear(t){var e=this;if(e.items.length){var n=e.controlChildren();gt(n,t=>{e.removeItem(t,!0)}),e.inputState(),t||e.updateOriginalInput(),e.trigger("clear")}}insertAtCaret(t){const e=this,n=e.caretPos,i=e.control;i.insertBefore(t,i.children[n]||null),e.setCaret(n+1)}deleteSelection(t){var e,n,i,r,o,s=this;e=t&&8===t.keyCode?-1:1,n={start:(o=s.control_input).selectionStart||0,length:(o.selectionEnd||0)-(o.selectionStart||0)};const a=[];if(s.activeItems.length)r=xt(s.activeItems,e),i=Dt(r),e>0&&i++,gt(s.activeItems,t=>a.push(t));else if((s.isFocused||"single"===s.settings.mode)&&s.items.length){const t=s.controlChildren();let i;e<0&&0===n.start&&0===n.length?i=t[s.caretPos-1]:e>0&&n.start===s.inputValue().length&&(i=t[s.caretPos]),void 0!==i&&a.push(i)}if(!s.shouldDelete(a,t))return!1;for(ut(t,!0),void 0!==i&&s.setCaret(i);a.length;)s.removeItem(a.pop());return s.inputState(),s.positionDropdown(),s.refreshOptions(!1),!0}shouldDelete(t,e){const n=t.map(t=>t.dataset.value);return!(!n.length||"function"==typeof this.settings.onDelete&&!1===this.settings.onDelete.call(this,n,e))}advanceSelection(t,e){var n,i,r=this;r.rtl&&(t*=-1),r.inputValue().length||(ht(At,e)||ht("shiftKey",e)?(i=(n=r.getLastActive(t))?n.classList.contains("active")?r.getAdjacent(n,t,"item"):n:t>0?r.control_input.nextElementSibling:r.control_input.previousElementSibling)&&(i.classList.contains("active")&&r.removeActiveItem(n),r.setActiveItemClass(i)):r.moveCaret(t))}moveCaret(t){}getLastActive(t){let e=this.control.querySelector(".last-active");if(e)return e;var n=this.control.querySelectorAll(".active");return n?xt(n,t):void 0}setCaret(t){this.caretPos=this.items.length}controlChildren(){return Array.from(this.control.querySelectorAll("[data-ts-item]"))}lock(){this.setLocked(!0)}unlock(){this.setLocked(!1)}setLocked(t=this.isReadOnly||this.isDisabled){this.isLocked=t,this.refreshState()}disable(){this.setDisabled(!0),this.close()}enable(){this.setDisabled(!1)}setDisabled(t){this.focus_node.tabIndex=t?-1:this.tabIndex,this.isDisabled=t,this.input.disabled=t,this.control_input.disabled=t,this.setLocked()}setReadOnly(t){this.isReadOnly=t,this.input.readOnly=t,this.control_input.readOnly=t,this.setLocked()}destroy(){var t=this,e=t.revertSettings;t.trigger("destroy"),t.off(),t.wrapper.remove(),t.dropdown.remove(),t.input.innerHTML=e.innerHTML,t.input.tabIndex=e.tabIndex,kt(t.input,"tomselected","ts-hidden-accessible"),t._destroy(),delete t.input.tomselect}render(t,e){var n,i;const r=this;if("function"!=typeof this.settings.render[t])return null;if(!(i=r.settings.render[t].call(this,e,at)))return null;if(i=vt(i),"option"===t||"option_create"===t?e[r.settings.disabledField]?Ot(i,{"aria-disabled":"true"}):Ot(i,{"data-selectable":""}):"optgroup"===t&&(n=e.group[r.settings.optgroupValueField],Ot(i,{"data-group":n}),e.group[r.settings.disabledField]&&Ot(i,{"data-disabled":""})),"option"===t||"item"===t){const n=st(e[r.settings.valueField]);Ot(i,{"data-value":n}),"item"===t?(wt(i,r.settings.itemClass),Ot(i,{"data-ts-item":""})):(wt(i,r.settings.optionClass),Ot(i,{role:"option",id:e.$id}),e.$div=i,r.options[n]=e)}return i}_render(t,e){const n=this.render(t,e);if(null==n)throw"HTMLElement expected";return n}clearCache(){gt(this.options,t=>{t.$div&&(t.$div.remove(),delete t.$div)})}uncacheValue(t){const e=this.getOption(t);e&&e.remove()}canCreate(t){return this.settings.create&&t.length>0&&this.settings.createFilter.call(this,t)}hook(t,e,n){var i=this,r=i[e];i[e]=function(){var e,o;return"after"===t&&(e=r.apply(i,arguments)),o=n.apply(i,arguments),"instead"===t?o:("before"===t&&(e=r.apply(i,arguments)),e)}}}const Ft=t=>"boolean"==typeof t?t?"1":"0":t+"",jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Rt=t=>"string"==typeof t&&t.indexOf("<")>-1;const $t=t=>"string"==typeof t&&t.indexOf("<")>-1;const Ht=(t,e,n,i)=>{t.addEventListener(e,n,i)},qt=t=>"string"==typeof t&&t.indexOf("<")>-1,Vt=(t,e)=>{((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(e,(e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)})};const zt=t=>"string"==typeof t&&t.indexOf("<")>-1;const Bt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Wt=t=>(Array.isArray(t)||(t=[t]),t);const Ut=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},Yt=t=>"string"==typeof t&&t.indexOf("<")>-1,Zt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},Gt=t=>(Array.isArray(t)||(t=[t]),t);const Kt=(t,e,n,i)=>{t.addEventListener(e,n,i)};const Jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Xt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Qt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(te(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},te=t=>"string"==typeof t&&t.indexOf("<")>-1;const ee=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))}),e.filter(Boolean)},ne=t=>(Array.isArray(t)||(t=[t]),t);Pt.define("change_listener",function(){var t,e,n,i;t=this.input,e="change",n=()=>{this.sync()},t.addEventListener(e,n,i)}),Pt.define("checkbox_options",function(t){var e=this,n=e.onOptionSelect;e.settings.hideSelected=!1;const i=Object.assign({className:"tomselect-checkbox",checkedClassNames:void 0,uncheckedClassNames:void 0},t);var r=function(t,e){e?(t.checked=!0,i.uncheckedClassNames&&t.classList.remove(...i.uncheckedClassNames),i.checkedClassNames&&t.classList.add(...i.checkedClassNames)):(t.checked=!1,i.checkedClassNames&&t.classList.remove(...i.checkedClassNames),i.uncheckedClassNames&&t.classList.add(...i.uncheckedClassNames))},o=function(t){setTimeout(()=>{var e=t.querySelector("input."+i.className);e instanceof HTMLInputElement&&r(e,t.classList.contains("selected"))},1)};e.hook("after","setupTemplates",()=>{var t=e.settings.render.option;e.settings.render.option=(n,o)=>{var s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Rt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(t.call(e,n,o)),a=document.createElement("input");i.className&&a.classList.add(i.className),a.addEventListener("click",function(t){jt(t)}),a.type="checkbox";const l=null==(c=n[e.settings.valueField])?null:Ft(c);var c;return r(a,!!(l&&e.items.indexOf(l)>-1)),s.prepend(a),s}}),e.on("item_remove",t=>{var n=e.getOption(t);n&&(n.classList.remove("selected"),o(n))}),e.on("item_add",t=>{var n=e.getOption(t);n&&o(n)}),e.hook("instead","onOptionSelect",(t,i)=>{if(i.classList.contains("selected"))return i.classList.remove("selected"),e.removeItem(i.dataset.value),e.refreshOptions(),void jt(t,!0);n.call(e,t,i),o(i)})}),Pt.define("clear_button",function(t){const e=this,n=Object.assign({className:"clear-button",title:"Clear All",role:"button",tabindex:0,html:t=>`
×
`},t);e.on("initialize",()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if($t(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n));t.addEventListener("click",t=>{e.isLocked||(e.clear(),"single"===e.settings.mode&&e.settings.allowEmptyOption&&e.addItem(""),e.refreshOptions(!1),t.preventDefault(),t.stopPropagation())}),e.control.appendChild(t)})}),Pt.define("drag_drop",function(){var t=this;if("multi"!==t.settings.mode)return;var e=t.lock,n=t.unlock;let i,r=!0;t.hook("after","setupTemplates",()=>{var e=t.settings.render.item;t.settings.render.item=(n,o)=>{const s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(qt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(e.call(t,n,o));Vt(s,{draggable:"true"});const a=t=>{t.preventDefault(),s.classList.add("ts-drag-over"),l(s,i)},l=(t,e)=>{var n,i,r;void 0!==e&&(((t,e)=>{do{var n;if(t==(e=null==(n=e)?void 0:n.previousElementSibling))return!0}while(e&&e.previousElementSibling);return!1})(e,s)?(i=e,null==(r=(n=t).parentNode)||r.insertBefore(i,n.nextSibling)):((t,e)=>{var n;null==(n=t.parentNode)||n.insertBefore(e,t)})(t,e))};return Ht(s,"mousedown",t=>{r||((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t),t.stopPropagation()}),Ht(s,"dragstart",t=>{i=s,setTimeout(()=>{s.classList.add("ts-dragging")},0)}),Ht(s,"dragenter",a),Ht(s,"dragover",a),Ht(s,"dragleave",()=>{s.classList.remove("ts-drag-over")}),Ht(s,"dragend",()=>{var e;document.querySelectorAll(".ts-drag-over").forEach(t=>t.classList.remove("ts-drag-over")),null==(e=i)||e.classList.remove("ts-dragging"),i=void 0;var n=[];t.control.querySelectorAll("[data-value]").forEach(t=>{if(t.dataset.value){let e=t.dataset.value;e&&n.push(e)}}),t.setValue(n)}),s}}),t.hook("instead","lock",()=>(r=!1,e.call(t))),t.hook("instead","unlock",()=>(r=!0,n.call(t)))}),Pt.define("dropdown_header",function(t){const e=this,n=Object.assign({title:"Untitled",headerClass:"dropdown-header",titleRowClass:"dropdown-header-title",labelClass:"dropdown-header-label",closeClass:"dropdown-header-close",html:t=>'
'+t.title+'×
'},t);e.on("initialize",()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(zt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n)),i=t.querySelector("."+n.closeClass);i&&i.addEventListener("click",t=>{((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t,!0),e.close()}),e.dropdown.insertBefore(t,e.dropdown.firstChild)})}),Pt.define("caret_position",function(){var t=this;t.hook("instead","setCaret",e=>{"single"!==t.settings.mode&&t.control.contains(t.control_input)?(e=Math.max(0,Math.min(t.items.length,e)))==t.caretPos||t.isPending||t.controlChildren().forEach((n,i)=>{i{if(!t.isFocused)return;const n=t.getLastActive(e);if(n){const i=((t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n})(n);t.setCaret(e>0?i+1:i),t.setActiveItem(),((t,...e)=>{var n=Bt(e);(t=Wt(t)).map(t=>{n.map(e=>{t.classList.remove(e)})})})(n,"last-active")}else t.setCaret(t.caretPos+e)})}),Pt.define("dropdown_input",function(){const t=this;t.settings.shouldOpen=!0,t.hook("before","setup",()=>{var e;t.focus_node=t.control,((t,...e)=>{var n=Zt(e);(t=Gt(t)).map(t=>{n.map(e=>{t.classList.add(e)})})})(t.control_input,"dropdown-input");const n=Ut('");for(var S=1;S<=7;S+=1){var x=3+this.options.firstDay+S,D=document.createElement("div");D.innerHTML=this.weekdayName(x),D.title=this.weekdayName(x,"long"),E.appendChild(D)}var O=document.createElement("div");O.className=a.containerDays;var L=this.calcSkipDays(i);this.options.showWeekNumbers&&L&&O.appendChild(this.renderWeekNumber(i));for(var C=0;C1&&1===this.datePicked.length){var r=this.options.minDays-1,o=this.datePicked[0].clone().subtract(r,"day"),c=this.datePicked[0].clone().add(r,"day");t.isBetween(o,this.datePicked[0],"(]")&&e.classList.add(a.isLocked),t.isBetween(this.datePicked[0],c,"[)")&&e.classList.add(a.isLocked)}if(this.options.maxDays&&1===this.datePicked.length){var u=this.options.maxDays;o=this.datePicked[0].clone().subtract(u,"day"),c=this.datePicked[0].clone().add(u,"day"),t.isSameOrBefore(o)&&e.classList.add(a.isLocked),t.isSameOrAfter(c)&&e.classList.add(a.isLocked)}return this.options.selectForward&&1===this.datePicked.length&&t.isBefore(this.datePicked[0])&&e.classList.add(a.isLocked),this.options.selectBackward&&1===this.datePicked.length&&t.isAfter(this.datePicked[0])&&e.classList.add(a.isLocked),l.dateIsLocked(t,this.options,this.datePicked)&&e.classList.add(a.isLocked),this.options.highlightedDays.length&&this.options.highlightedDays.filter(function(e){return e instanceof Array?t.isBetween(e[0],e[1],"[]"):e.isSame(t,"day")}).length&&e.classList.add(a.isHighlighted),e.tabIndex=e.classList.contains("is-locked")?-1:0,this.emit("render:day",e,t),e},e.prototype.renderFooter=function(){var t=document.createElement("div");if(t.className=a.containerFooter,this.options.footerHTML?t.innerHTML=this.options.footerHTML:t.innerHTML='\n \n \n \n ",this.options.singleMode){if(1===this.datePicked.length){var e=this.datePicked[0].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=e}}else if(1===this.datePicked.length&&t.querySelector("."+a.buttonApply).setAttribute("disabled",""),2===this.datePicked.length){e=this.datePicked[0].format(this.options.format,this.options.lang);var n=this.datePicked[1].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=""+e+this.options.delimiter+n}return this.emit("render:footer",t),t},e.prototype.renderWeekNumber=function(t){var e=document.createElement("div"),n=t.getWeek(this.options.firstDay);return e.className=a.weekNumber,e.innerHTML=53===n&&0===t.getMonth()?"53 / 1":n,e},e.prototype.renderTooltip=function(){var t=document.createElement("div");return t.className=a.containerTooltip,t},e.prototype.weekdayName=function(t,e){return void 0===e&&(e="short"),new Date(1970,0,t,12,0,0,0).toLocaleString(this.options.lang,{weekday:e})},e.prototype.calcSkipDays=function(t){var e=t.getDay()-this.options.firstDay;return e<0&&(e+=7),e},e}(o.LPCore);e.Calendar=c},function(t,e,n){"use strict";var i,r=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),o=this&&this.__assign||function(){return(o=Object.assign||function(t){for(var e,n=1,i=arguments.length;n',nextMonth:'',reset:'\n \n \n '},tooltipText:{one:"day",other:"days"}},n.options=o(o({},n.options),e.element.dataset),Object.keys(n.options).forEach(function(t){"true"!==n.options[t]&&"false"!==n.options[t]||(n.options[t]="true"===n.options[t])});var i=o(o({},n.options.dropdowns),e.dropdowns),r=o(o({},n.options.buttonText),e.buttonText),s=o(o({},n.options.tooltipText),e.tooltipText);n.options=o(o({},n.options),e),n.options.dropdowns=o({},i),n.options.buttonText=o({},r),n.options.tooltipText=o({},s),n.options.elementEnd||(n.options.allowRepick=!1),n.options.lockDays.length&&(n.options.lockDays=a.DateTime.convertArray(n.options.lockDays,n.options.lockDaysFormat)),n.options.highlightedDays.length&&(n.options.highlightedDays=a.DateTime.convertArray(n.options.highlightedDays,n.options.highlightedDaysFormat));var l=n.parseInput(),c=l[0],u=l[1];n.options.startDate&&(n.options.singleMode||n.options.endDate)&&(c=new a.DateTime(n.options.startDate,n.options.format,n.options.lang)),c&&n.options.endDate&&(u=new a.DateTime(n.options.endDate,n.options.format,n.options.lang)),c instanceof a.DateTime&&!isNaN(c.getTime())&&(n.options.startDate=c),n.options.startDate&&u instanceof a.DateTime&&!isNaN(u.getTime())&&(n.options.endDate=u),!n.options.singleMode||n.options.startDate instanceof a.DateTime||(n.options.startDate=null),n.options.singleMode||n.options.startDate instanceof a.DateTime&&n.options.endDate instanceof a.DateTime||(n.options.startDate=null,n.options.endDate=null);for(var d=0;dwindow.innerHeight,c=e.top+o-n.height>=n.height;l&&c&&(s=e.top+o-n.height)}if(/left|right/.test(i[0])||i[1]&&"auto"!==i[1]&&/left|right/.test(i[1]))a=/left|right/.test(i[0])?e[i[0]]+r:e[i[1]]+r,"right"!==i[0]&&"right"!==i[1]||(a-=n.width);else{a=e.left+r,l=e.left+n.width>window.innerWidth;var u=e.right+r-n.width>=0;l&&u&&(a=e.right+r-n.width)}return{left:a,top:s}},e}(s.EventEmitter);e.LPCore=c},function(t,e,n){"use strict";var i,r="object"==typeof Reflect?Reflect:null,o=r&&"function"==typeof r.apply?r.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};i=r&&"function"==typeof r.ownKeys?r.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var l=10;function c(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function u(t,e,n,i){var r,o,s,a;if("function"!=typeof n)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof n);if(void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),o=t._events),s=o[e]),void 0===s)s=o[e]=n,++t._eventsCount;else if("function"==typeof s?s=o[e]=i?[n,s]:[s,n]:i?s.unshift(n):s.push(n),(r=c(t))>0&&s.length>r&&!s.warned){s.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=t,l.type=e,l.count=s.length,a=l,console&&console.warn&&console.warn(a)}return t}function d(){for(var t=[],e=0;e0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var l=r[t];if(void 0===l)return!1;if("function"==typeof l)o(l,this,e);else{var c=l.length,u=f(l,c);for(n=0;n=0;o--)if(n[o]===e||n[o].listener===e){s=n[o].listener,r=o;break}if(r<0)return this;0===r?n.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},a.prototype.listeners=function(t){return p(this,t,!0)},a.prototype.rawListeners=function(t){return p(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):m.call(t,e)},a.prototype.listenerCount=m,a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(t,e,n){(e=n(9)(!1)).push([t.i,':root{--litepicker-container-months-color-bg: #fff;--litepicker-container-months-box-shadow-color: #ddd;--litepicker-footer-color-bg: #fafafa;--litepicker-footer-box-shadow-color: #ddd;--litepicker-tooltip-color-bg: #fff;--litepicker-month-header-color: #333;--litepicker-button-prev-month-color: #9e9e9e;--litepicker-button-next-month-color: #9e9e9e;--litepicker-button-prev-month-color-hover: #2196f3;--litepicker-button-next-month-color-hover: #2196f3;--litepicker-month-width: calc(var(--litepicker-day-width) * 7);--litepicker-month-weekday-color: #9e9e9e;--litepicker-month-week-number-color: #9e9e9e;--litepicker-day-width: 38px;--litepicker-day-color: #333;--litepicker-day-color-hover: #2196f3;--litepicker-is-today-color: #f44336;--litepicker-is-in-range-color: #bbdefb;--litepicker-is-locked-color: #9e9e9e;--litepicker-is-start-color: #fff;--litepicker-is-start-color-bg: #2196f3;--litepicker-is-end-color: #fff;--litepicker-is-end-color-bg: #2196f3;--litepicker-button-cancel-color: #fff;--litepicker-button-cancel-color-bg: #9e9e9e;--litepicker-button-apply-color: #fff;--litepicker-button-apply-color-bg: #2196f3;--litepicker-button-reset-color: #909090;--litepicker-button-reset-color-hover: #2196f3;--litepicker-highlighted-day-color: #333;--litepicker-highlighted-day-color-bg: #ffeb3b}.show-week-numbers{--litepicker-month-width: calc(var(--litepicker-day-width) * 8)}.litepicker{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-size:0.8em;display:none}.litepicker button{border:none;background:none}.litepicker .container__main{display:-webkit-box;display:-ms-flexbox;display:flex}.litepicker .container__months{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background-color:var(--litepicker-container-months-color-bg);border-radius:5px;-webkit-box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);width:calc(var(--litepicker-month-width) + 10px);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months.columns-2{width:calc((var(--litepicker-month-width) * 2) + 20px)}.litepicker .container__months.columns-3{width:calc((var(--litepicker-month-width) * 3) + 30px)}.litepicker .container__months.columns-4{width:calc((var(--litepicker-month-width) * 4) + 40px)}.litepicker .container__months.split-view .month-item-header .button-previous-month,.litepicker .container__months.split-view .month-item-header .button-next-month{visibility:visible}.litepicker .container__months .month-item{padding:5px;width:var(--litepicker-month-width);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months .month-item-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-weight:500;padding:10px 5px;text-align:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--litepicker-month-header-color)}.litepicker .container__months .month-item-header div{-webkit-box-flex:1;-ms-flex:1;flex:1}.litepicker .container__months .month-item-header div>.month-item-name{margin-right:5px}.litepicker .container__months .month-item-header div>.month-item-year{padding:0}.litepicker .container__months .month-item-header .reset-button{color:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button>svg{fill:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button *{pointer-events:none}.litepicker .container__months .month-item-header .reset-button:hover{color:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .reset-button:hover>svg{fill:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .button-previous-month,.litepicker .container__months .month-item-header .button-next-month{visibility:hidden;text-decoration:none;padding:3px 5px;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__months .month-item-header .button-previous-month *,.litepicker .container__months .month-item-header .button-next-month *{pointer-events:none}.litepicker .container__months .month-item-header .button-previous-month{color:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month>svg,.litepicker .container__months .month-item-header .button-previous-month>img{fill:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month:hover{color:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-previous-month:hover>svg{fill:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month{color:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month>svg,.litepicker .container__months .month-item-header .button-next-month>img{fill:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month:hover{color:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month:hover>svg{fill:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-weekdays-row{display:-webkit-box;display:-ms-flexbox;display:flex;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;color:var(--litepicker-month-weekday-color)}.litepicker .container__months .month-item-weekdays-row>div{padding:5px 0;font-size:85%;-webkit-box-flex:1;-ms-flex:1;flex:1;width:var(--litepicker-day-width);text-align:center}.litepicker .container__months .month-item:first-child .button-previous-month{visibility:visible}.litepicker .container__months .month-item:last-child .button-next-month{visibility:visible}.litepicker .container__months .month-item.no-previous-month .button-previous-month{visibility:hidden}.litepicker .container__months .month-item.no-next-month .button-next-month{visibility:hidden}.litepicker .container__days{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;text-align:center;-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__days>div,.litepicker .container__days>a{padding:5px 0;width:var(--litepicker-day-width)}.litepicker .container__days .day-item{color:var(--litepicker-day-color);text-align:center;text-decoration:none;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__days .day-item:hover{color:var(--litepicker-day-color-hover);-webkit-box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover);box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover)}.litepicker .container__days .day-item.is-today{color:var(--litepicker-is-today-color)}.litepicker .container__days .day-item.is-locked{color:var(--litepicker-is-locked-color)}.litepicker .container__days .day-item.is-locked:hover{color:var(--litepicker-is-locked-color);-webkit-box-shadow:none;box-shadow:none;cursor:default}.litepicker .container__days .day-item.is-in-range{background-color:var(--litepicker-is-in-range-color);border-radius:0}.litepicker .container__days .day-item.is-start-date{color:var(--litepicker-is-start-color);background-color:var(--litepicker-is-start-color-bg);border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-flipped{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date{color:var(--litepicker-is-end-color);background-color:var(--litepicker-is-end-color-bg);border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date.is-flipped{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-end-date{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-highlighted{color:var(--litepicker-highlighted-day-color);background-color:var(--litepicker-highlighted-day-color-bg)}.litepicker .container__days .week-number{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:var(--litepicker-month-week-number-color);font-size:85%}.litepicker .container__footer{text-align:right;padding:10px 5px;margin:0 5px;background-color:var(--litepicker-footer-color-bg);-webkit-box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);border-bottom-left-radius:5px;border-bottom-right-radius:5px}.litepicker .container__footer .preview-date-range{margin-right:10px;font-size:90%}.litepicker .container__footer .button-cancel{background-color:var(--litepicker-button-cancel-color-bg);color:var(--litepicker-button-cancel-color);border:0;padding:3px 7px 4px;border-radius:3px}.litepicker .container__footer .button-cancel *{pointer-events:none}.litepicker .container__footer .button-apply{background-color:var(--litepicker-button-apply-color-bg);color:var(--litepicker-button-apply-color);border:0;padding:3px 7px 4px;border-radius:3px;margin-left:10px;margin-right:10px}.litepicker .container__footer .button-apply:disabled{opacity:0.7}.litepicker .container__footer .button-apply *{pointer-events:none}.litepicker .container__tooltip{position:absolute;margin-top:-4px;padding:4px 8px;border-radius:4px;background-color:var(--litepicker-tooltip-color-bg);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25);white-space:nowrap;font-size:11px;pointer-events:none;visibility:hidden}.litepicker .container__tooltip:before{position:absolute;bottom:-5px;left:calc(50% - 5px);border-top:5px solid rgba(0,0,0,0.12);border-right:5px solid transparent;border-left:5px solid transparent;content:""}.litepicker .container__tooltip:after{position:absolute;bottom:-4px;left:calc(50% - 4px);border-top:4px solid var(--litepicker-tooltip-color-bg);border-right:4px solid transparent;border-left:4px solid transparent;content:""}\n',""]),e.locals={showWeekNumbers:"show-week-numbers",litepicker:"litepicker",containerMain:"container__main",containerMonths:"container__months",columns2:"columns-2",columns3:"columns-3",columns4:"columns-4",splitView:"split-view",monthItemHeader:"month-item-header",buttonPreviousMonth:"button-previous-month",buttonNextMonth:"button-next-month",monthItem:"month-item",monthItemName:"month-item-name",monthItemYear:"month-item-year",resetButton:"reset-button",monthItemWeekdaysRow:"month-item-weekdays-row",noPreviousMonth:"no-previous-month",noNextMonth:"no-next-month",containerDays:"container__days",dayItem:"day-item",isToday:"is-today",isLocked:"is-locked",isInRange:"is-in-range",isStartDate:"is-start-date",isFlipped:"is-flipped",isEndDate:"is-end-date",isHighlighted:"is-highlighted",weekNumber:"week-number",containerFooter:"container__footer",previewDateRange:"preview-date-range",buttonCancel:"button-cancel",buttonApply:"button-apply",containerTooltip:"container__tooltip"},t.exports=e},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=function(t,e){var n,i,r,o=t[1]||"",s=t[3];if(!s)return o;if(e&&"function"==typeof btoa){var a=(n=s,i=btoa(unescape(encodeURIComponent(JSON.stringify(n)))),r="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(i),"/*# ".concat(r," */")),l=s.sources.map(function(t){return"/*# sourceURL=".concat(s.sourceRoot||"").concat(t," */")});return[o].concat(l).concat([a]).join("\n")}return[o].join("\n")}(e,t);return e[2]?"@media ".concat(e[2]," {").concat(n,"}"):n}).join("")},e.i=function(t,n,i){"string"==typeof t&&(t=[[null,t,""]]);var r={};if(i)for(var o=0;othis.options.endDate.getTime()&&(this.options.endDate=this.options.startDate.clone(),this.options.startDate=new r.DateTime(t,this.options.format,this.options.lang)),this.updateInput())},o.Litepicker.prototype.setDateRange=function(t,e,n){void 0===n&&(n=!1),this.triggerElement=void 0;var i=new r.DateTime(t,this.options.format,this.options.lang),o=new r.DateTime(e,this.options.format,this.options.lang);(this.options.disallowLockDaysInRange?s.rangeIsLocked([i,o],this.options):s.dateIsLocked(i,this.options,[i,o])||s.dateIsLocked(o,this.options,[i,o]))&&!n?this.emit("error:range",[i,o]):(this.setStartDate(i),this.setEndDate(o),this.options.inlineMode&&this.render(),this.updateInput(),this.emit("selected",this.getStartDate(),this.getEndDate()))},o.Litepicker.prototype.gotoDate=function(t,e){void 0===e&&(e=0);var n=new r.DateTime(t);n.setDate(1),this.calendars[e]=n.clone(),this.render()},o.Litepicker.prototype.setLockDays=function(t){this.options.lockDays=r.DateTime.convertArray(t,this.options.lockDaysFormat),this.render()},o.Litepicker.prototype.setHighlightedDays=function(t){this.options.highlightedDays=r.DateTime.convertArray(t,this.options.highlightedDaysFormat),this.render()},o.Litepicker.prototype.setOptions=function(t){delete t.element,delete t.elementEnd,delete t.parentEl,t.startDate&&(t.startDate=new r.DateTime(t.startDate,this.options.format,this.options.lang)),t.endDate&&(t.endDate=new r.DateTime(t.endDate,this.options.format,this.options.lang));var e=i(i({},this.options.dropdowns),t.dropdowns),n=i(i({},this.options.buttonText),t.buttonText),o=i(i({},this.options.tooltipText),t.tooltipText);this.options=i(i({},this.options),t),this.options.dropdowns=i({},e),this.options.buttonText=i({},n),this.options.tooltipText=i({},o),!this.options.singleMode||this.options.startDate instanceof r.DateTime||(this.options.startDate=null,this.options.endDate=null),this.options.singleMode||this.options.startDate instanceof r.DateTime&&this.options.endDate instanceof r.DateTime||(this.options.startDate=null,this.options.endDate=null);for(var s=0;sMath.abs(o),a=t.options.numberOfMonths,l=null,c=!1,u="",d=Array.from(t.ui.querySelectorAll(".month-item"));if(s){var h=t.DateTime(t.ui.querySelector(".day-item").dataset.time),p=Number("".concat(1-Math.abs(r)/100)),m=0;if(r>0){m=-Math.abs(r),l=h.clone().add(a,"month");var f=t.options.maxDate;c=!f||l.isSameOrBefore(t.DateTime(f),"month"),u="next"}else{m=Math.abs(r),l=h.clone().subtract(a,"month");var g=t.options.minDate;c=!g||l.isSameOrAfter(t.DateTime(g),"month"),u="prev"}c&&d.map(function(t){t.style.opacity=p,t.style.transform="translateX(".concat(m,"px)")})}Math.abs(r)+Math.abs(o)>100&&s&&l&&c&&(t.touchTargetMonth=u,t.gotoDate(l))}},!!n&&{passive:!0}),t.ui.addEventListener("touchend",function(e){t.touchTargetMonth||Array.from(t.ui.querySelectorAll(".month-item")).map(function(t){t.style.transform="translateX(0px)",t.style.opacity=1}),t.xTouchDown=null,t.yTouchDown=null},!!n&&{passive:!0})}})},function(t,e,n){var i=n(7);"string"==typeof i&&(i=[[t.i,i,""]]);var r={insert:function(t){var e=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;window.disableLitepickerStyles||(n?n.nextSibling?e.insertBefore(t,n.nextSibling):e.appendChild(t):e.insertBefore(t,e.firstChild),window._lastElementInsertedByStyleLoader=t)},singleton:!1};n(1)(i,r),i.locals&&(t.exports=i.locals)},function(t,e,n){(e=n(0)(!1)).push([t.i,':root {\n --litepicker-mobilefriendly-backdrop-color-bg: #000;\n}\n\n.litepicker-backdrop {\n display: none;\n background-color: var(--litepicker-mobilefriendly-backdrop-color-bg);\n opacity: 0.3;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n.litepicker-open {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] {\n transform: translate(-50%, -50%);\n font-size: 1.1rem;\n --litepicker-container-months-box-shadow-color: #616161;\n}\n.litepicker.mobilefriendly-portrait {\n --litepicker-day-width: 13.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n.litepicker.mobilefriendly-landscape {\n --litepicker-day-width: 5.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__months .month-item-header {\n height: var(--litepicker-day-width);\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__days > div {\n height: var(--litepicker-day-width);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item {\n transform-origin: center;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-next {\n animation-name: lp-bounce-target-next;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-prev {\n animation-name: lp-bounce-target-prev;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n@keyframes lp-bounce-target-next {\n from {\n transform: translateX(100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}\n\n@keyframes lp-bounce-target-prev {\n from {\n transform: translateX(-100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}',""]),t.exports=e}])},3829:function(t,e,n){"use strict";n.r(e)},2481:function(t,e,n){"use strict";var i=n(8252),r=n(1958),o=TypeError;t.exports=function(t){if(i(t))return t;throw new o(r(t)+" is not a function")}},7938:function(t,e,n){"use strict";var i=n(2666),r=n(3369),o=n(1250).f,s=i("unscopables"),a=Array.prototype;void 0===a[s]&&o(a,s,{configurable:!0,value:r(null)}),t.exports=function(t){a[s][t]=!0}},3162:function(t,e,n){"use strict";var i=n(8271),r=String,o=TypeError;t.exports=function(t){if(i(t))return t;throw new o(r(t)+" is not an object")}},8658:function(t,e,n){"use strict";var i=n(2364),r=n(9283),o=n(6013),s=function(t){return function(e,n,s){var a=i(e),l=o(a);if(0===l)return!t&&-1;var c,u=r(s,l);if(t&&n!=n){for(;l>u;)if((c=a[u++])!=c)return!0}else for(;l>u;u++)if((t||u in a)&&a[u]===n)return t||u||0;return!t&&-1}};t.exports={includes:s(!0),indexOf:s(!1)}},7409:function(t,e,n){"use strict";var i=n(2289),r=i({}.toString),o=i("".slice);t.exports=function(t){return o(r(t),8,-1)}},4993:function(t,e,n){"use strict";var i=n(9522),r=n(5456),o=n(6056),s=n(1250);t.exports=function(t,e,n){for(var a=r(e),l=s.f,c=o.f,u=0;u0&&i[0]<4?1:+(i[0]+i[1])),!r&&s&&(!(i=s.match(/Edge\/(\d+)/))||i[1]>=74)&&(i=s.match(/Chrome\/(\d+)/))&&(r=+i[1]),t.exports=r},7725:function(t,e,n){"use strict";var i=n(3405),r=n(6056).f,o=n(232),s=n(3589),a=n(7214),l=n(4993),c=n(5129);t.exports=function(t,e){var n,u,d,h,p,m=t.target,f=t.global,g=t.stat;if(n=f?i:g?i[m]||a(m,{}):i[m]&&i[m].prototype)for(u in e){if(h=e[u],d=t.dontCallGetSet?(p=r(n,u))&&p.value:n[u],!c(f?u:m+(g?".":"#")+u,t.forced)&&void 0!==d){if(typeof h==typeof d)continue;l(h,d)}(t.sham||d&&d.sham)&&o(h,"sham",!0),s(n,u,h,t)}}},8930:function(t){"use strict";t.exports=function(t){try{return!!t()}catch(t){return!0}}},5647:function(t,e,n){"use strict";var i=n(8930);t.exports=!i(function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")})},3176:function(t,e,n){"use strict";var i=n(5647),r=Function.prototype.call;t.exports=i?r.bind(r):function(){return r.apply(r,arguments)}},3743:function(t,e,n){"use strict";var i=n(7101),r=n(9522),o=Function.prototype,s=i&&Object.getOwnPropertyDescriptor,a=r(o,"name"),l=a&&"something"===function(){}.name,c=a&&(!i||i&&s(o,"name").configurable);t.exports={EXISTS:a,PROPER:l,CONFIGURABLE:c}},2289:function(t,e,n){"use strict";var i=n(5647),r=Function.prototype,o=r.call,s=i&&r.bind.bind(o,o);t.exports=i?s:function(t){return function(){return o.apply(t,arguments)}}},3220:function(t,e,n){"use strict";var i=n(3405),r=n(8252);t.exports=function(t,e){return arguments.length<2?(n=i[t],r(n)?n:void 0):i[t]&&i[t][e];var n}},3377:function(t,e,n){"use strict";var i=n(2481),r=n(3022);t.exports=function(t,e){var n=t[e];return r(n)?void 0:i(n)}},3405:function(t,e,n){"use strict";var i=function(t){return t&&t.Math===Math&&t};t.exports=i("object"==typeof globalThis&&globalThis)||i("object"==typeof window&&window)||i("object"==typeof self&&self)||i("object"==typeof n.g&&n.g)||i("object"==typeof this&&this)||function(){return this}()||Function("return this")()},9522:function(t,e,n){"use strict";var i=n(2289),r=n(1724),o=i({}.hasOwnProperty);t.exports=Object.hasOwn||function(t,e){return o(r(t),e)}},4036:function(t){"use strict";t.exports={}},9810:function(t,e,n){"use strict";var i=n(3220);t.exports=i("document","documentElement")},1782:function(t,e,n){"use strict";var i=n(7101),r=n(8930),o=n(2998);t.exports=!i&&!r(function(){return 7!==Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a})},1792:function(t,e,n){"use strict";var i=n(2289),r=n(8930),o=n(7409),s=Object,a=i("".split);t.exports=r(function(){return!s("z").propertyIsEnumerable(0)})?function(t){return"String"===o(t)?a(t,""):s(t)}:s},4117:function(t,e,n){"use strict";var i=n(2289),r=n(8252),o=n(8486),s=i(Function.toString);r(o.inspectSource)||(o.inspectSource=function(t){return s(t)}),t.exports=o.inspectSource},4206:function(t,e,n){"use strict";var i,r,o,s=n(3337),a=n(3405),l=n(8271),c=n(232),u=n(9522),d=n(8486),h=n(4040),p=n(4036),m="Object already initialized",f=a.TypeError,g=a.WeakMap;if(s||d.state){var v=d.state||(d.state=new g);v.get=v.get,v.has=v.has,v.set=v.set,i=function(t,e){if(v.has(t))throw new f(m);return e.facade=t,v.set(t,e),e},r=function(t){return v.get(t)||{}},o=function(t){return v.has(t)}}else{var y=h("state");p[y]=!0,i=function(t,e){if(u(t,y))throw new f(m);return e.facade=t,c(t,y,e),e},r=function(t){return u(t,y)?t[y]:{}},o=function(t){return u(t,y)}}t.exports={set:i,get:r,has:o,enforce:function(t){return o(t)?r(t):i(t,{})},getterFor:function(t){return function(e){var n;if(!l(e)||(n=r(e)).type!==t)throw new f("Incompatible receiver, "+t+" required");return n}}}},8252:function(t){"use strict";var e="object"==typeof document&&document.all;t.exports=void 0===e&&void 0!==e?function(t){return"function"==typeof t||t===e}:function(t){return"function"==typeof t}},5129:function(t,e,n){"use strict";var i=n(8930),r=n(8252),o=/#|\.prototype\./,s=function(t,e){var n=l[a(t)];return n===u||n!==c&&(r(e)?i(e):!!e)},a=s.normalize=function(t){return String(t).replace(o,".").toLowerCase()},l=s.data={},c=s.NATIVE="N",u=s.POLYFILL="P";t.exports=s},3022:function(t){"use strict";t.exports=function(t){return null==t}},8271:function(t,e,n){"use strict";var i=n(8252);t.exports=function(t){return"object"==typeof t?null!==t:i(t)}},4214:function(t){"use strict";t.exports=!1},8944:function(t,e,n){"use strict";var i=n(3220),r=n(8252),o=n(8130),s=n(5537),a=Object;t.exports=s?function(t){return"symbol"==typeof t}:function(t){var e=i("Symbol");return r(e)&&o(e.prototype,a(t))}},6013:function(t,e,n){"use strict";var i=n(5531);t.exports=function(t){return i(t.length)}},4034:function(t,e,n){"use strict";var i=n(2289),r=n(8930),o=n(8252),s=n(9522),a=n(7101),l=n(3743).CONFIGURABLE,c=n(4117),u=n(4206),d=u.enforce,h=u.get,p=String,m=Object.defineProperty,f=i("".slice),g=i("".replace),v=i([].join),y=a&&!r(function(){return 8!==m(function(){},"length",{value:8}).length}),b=String(String).split("String"),_=t.exports=function(t,e,n){"Symbol("===f(p(e),0,7)&&(e="["+g(p(e),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),n&&n.getter&&(e="get "+e),n&&n.setter&&(e="set "+e),(!s(t,"name")||l&&t.name!==e)&&(a?m(t,"name",{value:e,configurable:!0}):t.name=e),y&&n&&s(n,"arity")&&t.length!==n.arity&&m(t,"length",{value:n.arity});try{n&&s(n,"constructor")&&n.constructor?a&&m(t,"prototype",{writable:!1}):t.prototype&&(t.prototype=void 0)}catch(t){}var i=d(t);return s(i,"source")||(i.source=v(b,"string"==typeof e?e:"")),t};Function.prototype.toString=_(function(){return o(this)&&h(this).source||c(this)},"toString")},7966:function(t){"use strict";var e=Math.ceil,n=Math.floor;t.exports=Math.trunc||function(t){var i=+t;return(i>0?n:e)(i)}},3369:function(t,e,n){"use strict";var i,r=n(3162),o=n(5422),s=n(7658),a=n(4036),l=n(9810),c=n(2998),u=n(4040),d="prototype",h="script",p=u("IE_PROTO"),m=function(){},f=function(t){return"<"+h+">"+t+""},g=function(t){t.write(f("")),t.close();var e=t.parentWindow.Object;return t=null,e},v=function(){try{i=new ActiveXObject("htmlfile")}catch(t){}var t,e,n;v="undefined"!=typeof document?document.domain&&i?g(i):(e=c("iframe"),n="java"+h+":",e.style.display="none",l.appendChild(e),e.src=String(n),(t=e.contentWindow.document).open(),t.write(f("document.F=Object")),t.close(),t.F):g(i);for(var r=s.length;r--;)delete v[d][s[r]];return v()};a[p]=!0,t.exports=Object.create||function(t,e){var n;return null!==t?(m[d]=r(t),n=new m,m[d]=null,n[p]=t):n=v(),void 0===e?n:o.f(n,e)}},5422:function(t,e,n){"use strict";var i=n(7101),r=n(3667),o=n(1250),s=n(3162),a=n(2364),l=n(7185);e.f=i&&!r?Object.defineProperties:function(t,e){s(t);for(var n,i=a(e),r=l(e),c=r.length,u=0;c>u;)o.f(t,n=r[u++],i[n]);return t}},1250:function(t,e,n){"use strict";var i=n(7101),r=n(1782),o=n(3667),s=n(3162),a=n(3704),l=TypeError,c=Object.defineProperty,u=Object.getOwnPropertyDescriptor,d="enumerable",h="configurable",p="writable";e.f=i?o?function(t,e,n){if(s(t),e=a(e),s(n),"function"==typeof t&&"prototype"===e&&"value"in n&&p in n&&!n[p]){var i=u(t,e);i&&i[p]&&(t[e]=n.value,n={configurable:h in n?n[h]:i[h],enumerable:d in n?n[d]:i[d],writable:!1})}return c(t,e,n)}:c:function(t,e,n){if(s(t),e=a(e),s(n),r)try{return c(t,e,n)}catch(t){}if("get"in n||"set"in n)throw new l("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},6056:function(t,e,n){"use strict";var i=n(7101),r=n(3176),o=n(6640),s=n(9299),a=n(2364),l=n(3704),c=n(9522),u=n(1782),d=Object.getOwnPropertyDescriptor;e.f=i?d:function(t,e){if(t=a(t),e=l(e),u)try{return d(t,e)}catch(t){}if(c(t,e))return s(!r(o.f,t,e),t[e])}},7469:function(t,e,n){"use strict";var i=n(6067),r=n(7658).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return i(t,r)}},4540:function(t,e){"use strict";e.f=Object.getOwnPropertySymbols},8130:function(t,e,n){"use strict";var i=n(2289);t.exports=i({}.isPrototypeOf)},6067:function(t,e,n){"use strict";var i=n(2289),r=n(9522),o=n(2364),s=n(8658).indexOf,a=n(4036),l=i([].push);t.exports=function(t,e){var n,i=o(t),c=0,u=[];for(n in i)!r(a,n)&&r(i,n)&&l(u,n);for(;e.length>c;)r(i,n=e[c++])&&(~s(u,n)||l(u,n));return u}},7185:function(t,e,n){"use strict";var i=n(6067),r=n(7658);t.exports=Object.keys||function(t){return i(t,r)}},6640:function(t,e){"use strict";var n={}.propertyIsEnumerable,i=Object.getOwnPropertyDescriptor,r=i&&!n.call({1:2},1);e.f=r?function(t){var e=i(this,t);return!!e&&e.enumerable}:n},5519:function(t,e,n){"use strict";var i=n(3176),r=n(8252),o=n(8271),s=TypeError;t.exports=function(t,e){var n,a;if("string"===e&&r(n=t.toString)&&!o(a=i(n,t)))return a;if(r(n=t.valueOf)&&!o(a=i(n,t)))return a;if("string"!==e&&r(n=t.toString)&&!o(a=i(n,t)))return a;throw new s("Can't convert object to primitive value")}},5456:function(t,e,n){"use strict";var i=n(3220),r=n(2289),o=n(7469),s=n(4540),a=n(3162),l=r([].concat);t.exports=i("Reflect","ownKeys")||function(t){var e=o.f(a(t)),n=s.f;return n?l(e,n(t)):e}},2341:function(t,e,n){"use strict";var i=n(3022),r=TypeError;t.exports=function(t){if(i(t))throw new r("Can't call method on "+t);return t}},4040:function(t,e,n){"use strict";var i=n(8762),r=n(2161),o=i("keys");t.exports=function(t){return o[t]||(o[t]=r(t))}},8486:function(t,e,n){"use strict";var i=n(4214),r=n(3405),o=n(7214),s="__core-js_shared__",a=t.exports=r[s]||o(s,{});(a.versions||(a.versions=[])).push({version:"3.49.0",mode:i?"pure":"global",copyright:"© 2013–2025 Denis Pushkarev (zloirock.ru), 2025–2026 CoreJS Company (core-js.io). All rights reserved.",license:"https://github.com/zloirock/core-js/blob/v3.49.0/LICENSE",source:"https://github.com/zloirock/core-js"})},8762:function(t,e,n){"use strict";var i=n(8486);t.exports=function(t,e){return i[t]||(i[t]=e||{})}},1520:function(t,e,n){"use strict";var i=n(5168),r=n(8930),o=n(3405).String;t.exports=!!Object.getOwnPropertySymbols&&!r(function(){var t=Symbol("symbol detection");return!o(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&i&&i<41})},9283:function(t,e,n){"use strict";var i=n(136),r=Math.max,o=Math.min;t.exports=function(t,e){var n=i(t);return n<0?r(n+e,0):o(n,e)}},2364:function(t,e,n){"use strict";var i=n(1792),r=n(2341);t.exports=function(t){return i(r(t))}},136:function(t,e,n){"use strict";var i=n(7966);t.exports=function(t){var e=+t;return e!=e||0===e?0:i(e)}},5531:function(t,e,n){"use strict";var i=n(136),r=Math.min;t.exports=function(t){var e=i(t);return e>0?r(e,9007199254740991):0}},1724:function(t,e,n){"use strict";var i=n(2341),r=Object;t.exports=function(t){return r(i(t))}},4610:function(t,e,n){"use strict";var i=n(3176),r=n(8271),o=n(8944),s=n(3377),a=n(5519),l=n(2666),c=TypeError,u=l("toPrimitive");t.exports=function(t,e){if(!r(t)||o(t))return t;var n,l=s(t,u);if(l){if(void 0===e&&(e="default"),n=i(l,t,e),!r(n)||o(n))return n;throw new c("Can't convert object to primitive value")}return void 0===e&&(e="number"),a(t,e)}},3704:function(t,e,n){"use strict";var i=n(4610),r=n(8944);t.exports=function(t){var e=i(t,"string");return r(e)?e:e+""}},1958:function(t){"use strict";var e=String;t.exports=function(t){try{return e(t)}catch(t){return"Object"}}},2161:function(t,e,n){"use strict";var i=n(2289),r=0,o=Math.random(),s=i(1.1.toString);t.exports=function(t){return"Symbol("+(void 0===t?"":t)+")_"+s(++r+o,36)}},5537:function(t,e,n){"use strict";var i=n(1520);t.exports=i&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},3667:function(t,e,n){"use strict";var i=n(7101),r=n(8930);t.exports=i&&r(function(){return 42!==Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype})},3337:function(t,e,n){"use strict";var i=n(3405),r=n(8252),o=i.WeakMap;t.exports=r(o)&&/native code/.test(String(o))},2666:function(t,e,n){"use strict";var i=n(3405),r=n(8762),o=n(9522),s=n(2161),a=n(1520),l=n(5537),c=i.Symbol,u=r("wks"),d=l?c.for||c:c&&c.withoutSetter||s;t.exports=function(t){return o(u,t)||(u[t]=a&&o(c,t)?c[t]:d("Symbol."+t)),u[t]}},9690:function(t,e,n){"use strict";var i=n(7725),r=n(8658).includes,o=n(8930),s=n(7938),a=o(function(){return!Array(1).includes()}),l=o(function(){return[,1].includes(void 0,1)});i({target:"Array",proto:!0,forced:a||l},{includes:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),s("includes")},2647:function(t,e,n){"use strict";n.d(e,{c9:function(){return bi},dw:function(){return xn},wB:function(){return wt}});class i extends Error{}class r extends i{constructor(t){super(`Invalid DateTime: ${t.toMessage()}`)}}class o extends i{constructor(t){super(`Invalid Interval: ${t.toMessage()}`)}}class s extends i{constructor(t){super(`Invalid Duration: ${t.toMessage()}`)}}class a extends i{}class l extends i{constructor(t){super(`Invalid unit ${t}`)}}class c extends i{}class u extends i{constructor(){super("Zone is an abstract class")}}const d="numeric",h="short",p="long",m={year:d,month:d,day:d},f={year:d,month:h,day:d},g={year:d,month:h,day:d,weekday:h},v={year:d,month:p,day:d},y={year:d,month:p,day:d,weekday:p},b={hour:d,minute:d},_={hour:d,minute:d,second:d},w={hour:d,minute:d,second:d,timeZoneName:h},k={hour:d,minute:d,second:d,timeZoneName:p},T={hour:d,minute:d,hourCycle:"h23"},E={hour:d,minute:d,second:d,hourCycle:"h23"},S={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:h},x={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:p},D={year:d,month:d,day:d,hour:d,minute:d},O={year:d,month:d,day:d,hour:d,minute:d,second:d},L={year:d,month:h,day:d,hour:d,minute:d},C={year:d,month:h,day:d,hour:d,minute:d,second:d},A={year:d,month:h,day:d,weekday:h,hour:d,minute:d},M={year:d,month:p,day:d,hour:d,minute:d,timeZoneName:h},I={year:d,month:p,day:d,hour:d,minute:d,second:d,timeZoneName:h},N={year:d,month:p,day:d,weekday:p,hour:d,minute:d,timeZoneName:p},P={year:d,month:p,day:d,weekday:p,hour:d,minute:d,second:d,timeZoneName:p};class F{get type(){throw new u}get name(){throw new u}get ianaName(){return this.name}get isUniversal(){throw new u}offsetName(t,e){throw new u}formatOffset(t,e){throw new u}offset(t){throw new u}equals(t){throw new u}get isValid(){throw new u}}let j=null;class R extends F{static get instance(){return null===j&&(j=new R),j}get type(){return"system"}get name(){return(new Intl.DateTimeFormat).resolvedOptions().timeZone}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return re(t,e,n)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){return-new Date(t).getTimezoneOffset()}equals(t){return"system"===t.type}get isValid(){return!0}}const $=new Map;const H={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6};const q=new Map;class V extends F{static create(t){let e=q.get(t);return void 0===e&&q.set(t,e=new V(t)),e}static resetCache(){q.clear(),$.clear()}static isValidSpecifier(t){return this.isValidZone(t)}static isValidZone(t){if(!t)return!1;try{return new Intl.DateTimeFormat("en-US",{timeZone:t}).format(),!0}catch(t){return!1}}constructor(t){super(),this.zoneName=t,this.valid=V.isValidZone(t)}get type(){return"iana"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return re(t,e,n,this.name)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){if(!this.valid)return NaN;const e=new Date(t);if(isNaN(e))return NaN;const n=function(t){let e=$.get(t);return void 0===e&&(e=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short"}),$.set(t,e)),e}(this.name);let[i,r,o,s,a,l,c]=n.formatToParts?function(t,e){const n=t.formatToParts(e),i=[];for(let t=0;t=0?d:1e3+d,(te({year:i,month:r,day:o,hour:24===a?0:a,minute:l,second:c,millisecond:0})-u)/6e4}equals(t){return"iana"===t.type&&t.name===this.name}get isValid(){return this.valid}}let z={};const B=new Map;function W(t,e={}){const n=JSON.stringify([t,e]);let i=B.get(n);return void 0===i&&(i=new Intl.DateTimeFormat(t,e),B.set(n,i)),i}const U=new Map;const Y=new Map;let Z=null;const G=new Map;function K(t){let e=G.get(t);return void 0===e&&(e=new Intl.DateTimeFormat(t).resolvedOptions(),G.set(t,e)),e}const J=new Map;function X(t,e,n,i){const r=t.listingMode();return"error"===r?null:"en"===r?n(e):i(e)}class Q{constructor(t,e,n){this.padTo=n.padTo||0,this.floor=n.floor||!1;const{padTo:i,floor:r,...o}=n;if(!e||Object.keys(o).length>0){const e={useGrouping:!1,...n};n.padTo>0&&(e.minimumIntegerDigits=n.padTo),this.inf=function(t,e={}){const n=JSON.stringify([t,e]);let i=U.get(n);return void 0===i&&(i=new Intl.NumberFormat(t,e),U.set(n,i)),i}(t,e)}}format(t){if(this.inf){const e=this.floor?Math.floor(t):t;return this.inf.format(e)}return Ut(this.floor?Math.floor(t):Kt(t,3),this.padTo)}}class tt{constructor(t,e,n){let i;if(this.opts=n,this.originalZone=void 0,this.opts.timeZone)this.dt=t;else if("fixed"===t.zone.type){const e=t.offset/60*-1,n=e>=0?`Etc/GMT+${e}`:`Etc/GMT${e}`;0!==t.offset&&V.create(n).valid?(i=n,this.dt=t):(i="UTC",this.dt=0===t.offset?t:t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone)}else"system"===t.zone.type?this.dt=t:"iana"===t.zone.type?(this.dt=t,i=t.zone.name):(i="UTC",this.dt=t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone);const r={...this.opts};r.timeZone=r.timeZone||i,this.dtf=W(e,r)}format(){return this.originalZone?this.formatToParts().map(({value:t})=>t).join(""):this.dtf.format(this.dt.toJSDate())}formatToParts(){const t=this.dtf.formatToParts(this.dt.toJSDate());return this.originalZone?t.map(t=>{if("timeZoneName"===t.type){const e=this.originalZone.offsetName(this.dt.ts,{locale:this.dt.locale,format:this.opts.timeZoneName});return{...t,value:e}}return t}):t}resolvedOptions(){return this.dtf.resolvedOptions()}}class et{constructor(t,e,n){this.opts={style:"long",...n},!e&&Ht()&&(this.rtf=function(t,e={}){const{base:n,...i}=e,r=JSON.stringify([t,i]);let o=Y.get(r);return void 0===o&&(o=new Intl.RelativeTimeFormat(t,e),Y.set(r,o)),o}(t,n))}format(t,e){return this.rtf?this.rtf.format(t,e):function(t,e,n="always",i=!1){const r={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."]},o=-1===["hours","minutes","seconds"].indexOf(t);if("auto"===n&&o){const n="days"===t;switch(e){case 1:return n?"tomorrow":`next ${r[t][0]}`;case-1:return n?"yesterday":`last ${r[t][0]}`;case 0:return n?"today":`this ${r[t][0]}`}}const s=Object.is(e,-0)||e<0,a=Math.abs(e),l=1===a,c=r[t],u=i?l?c[1]:c[2]||c[1]:l?r[t][0]:t;return s?`${a} ${u} ago`:`in ${a} ${u}`}(e,t,this.opts.numeric,"long"!==this.opts.style)}formatToParts(t,e){return this.rtf?this.rtf.formatToParts(t,e):[]}}const nt={firstDay:1,minimalDays:4,weekend:[6,7]};class it{static fromOpts(t){return it.create(t.locale,t.numberingSystem,t.outputCalendar,t.weekSettings,t.defaultToEN)}static create(t,e,n,i,r=!1){const o=t||wt.defaultLocale,s=o||(r?"en-US":Z||(Z=(new Intl.DateTimeFormat).resolvedOptions().locale,Z)),a=e||wt.defaultNumberingSystem,l=n||wt.defaultOutputCalendar,c=Bt(i)||wt.defaultWeekSettings;return new it(s,a,l,c,o)}static resetCache(){Z=null,B.clear(),U.clear(),Y.clear(),G.clear(),J.clear()}static fromObject({locale:t,numberingSystem:e,outputCalendar:n,weekSettings:i}={}){return it.create(t,e,n,i)}constructor(t,e,n,i,r){const[o,s,a]=function(t){const e=t.indexOf("-x-");-1!==e&&(t=t.substring(0,e));const n=t.indexOf("-u-");if(-1===n)return[t];{let e,i;try{e=W(t).resolvedOptions(),i=t}catch(r){const o=t.substring(0,n);e=W(o).resolvedOptions(),i=o}const{numberingSystem:r,calendar:o}=e;return[i,r,o]}}(t);this.locale=o,this.numberingSystem=e||s||null,this.outputCalendar=n||a||null,this.weekSettings=i,this.intl=function(t,e,n){return n||e?(t.includes("-u-")||(t+="-u"),n&&(t+=`-ca-${n}`),e&&(t+=`-nu-${e}`),t):t}(this.locale,this.numberingSystem,this.outputCalendar),this.weekdaysCache={format:{},standalone:{}},this.monthsCache={format:{},standalone:{}},this.meridiemCache=null,this.eraCache={},this.specifiedLocale=r,this.fastNumbersCached=null}get fastNumbers(){var t;return null==this.fastNumbersCached&&(this.fastNumbersCached=(!(t=this).numberingSystem||"latn"===t.numberingSystem)&&("latn"===t.numberingSystem||!t.locale||t.locale.startsWith("en")||"latn"===K(t.locale).numberingSystem)),this.fastNumbersCached}listingMode(){const t=this.isEnglish(),e=!(null!==this.numberingSystem&&"latn"!==this.numberingSystem||null!==this.outputCalendar&&"gregory"!==this.outputCalendar);return t&&e?"en":"intl"}clone(t){return t&&0!==Object.getOwnPropertyNames(t).length?it.create(t.locale||this.specifiedLocale,t.numberingSystem||this.numberingSystem,t.outputCalendar||this.outputCalendar,Bt(t.weekSettings)||this.weekSettings,t.defaultToEN||!1):this}redefaultToEN(t={}){return this.clone({...t,defaultToEN:!0})}redefaultToSystem(t={}){return this.clone({...t,defaultToEN:!1})}months(t,e=!1){return X(this,t,pe,()=>{const n="ja"===this.intl||this.intl.startsWith("ja-"),i=(e&=!n)?{month:t,day:"numeric"}:{month:t},r=e?"format":"standalone";if(!this.monthsCache[r][t]){const e=n?t=>this.dtFormatter(t,i).format():t=>this.extract(t,i,"month");this.monthsCache[r][t]=function(t){const e=[];for(let n=1;n<=12;n++){const i=bi.utc(2009,n,1);e.push(t(i))}return e}(e)}return this.monthsCache[r][t]})}weekdays(t,e=!1){return X(this,t,ve,()=>{const n=e?{weekday:t,year:"numeric",month:"long",day:"numeric"}:{weekday:t},i=e?"format":"standalone";return this.weekdaysCache[i][t]||(this.weekdaysCache[i][t]=function(t){const e=[];for(let n=1;n<=7;n++){const i=bi.utc(2016,11,13+n);e.push(t(i))}return e}(t=>this.extract(t,n,"weekday"))),this.weekdaysCache[i][t]})}meridiems(){return X(this,void 0,()=>ye,()=>{if(!this.meridiemCache){const t={hour:"numeric",hourCycle:"h12"};this.meridiemCache=[bi.utc(2016,11,13,9),bi.utc(2016,11,13,19)].map(e=>this.extract(e,t,"dayperiod"))}return this.meridiemCache})}eras(t){return X(this,t,ke,()=>{const e={era:t};return this.eraCache[t]||(this.eraCache[t]=[bi.utc(-40,1,1),bi.utc(2017,1,1)].map(t=>this.extract(t,e,"era"))),this.eraCache[t]})}extract(t,e,n){const i=this.dtFormatter(t,e).formatToParts().find(t=>t.type.toLowerCase()===n);return i?i.value:null}numberFormatter(t={}){return new Q(this.intl,t.forceSimple||this.fastNumbers,t)}dtFormatter(t,e={}){return new tt(t,this.intl,e)}relFormatter(t={}){return new et(this.intl,this.isEnglish(),t)}listFormatter(t={}){return function(t,e={}){const n=JSON.stringify([t,e]);let i=z[n];return i||(i=new Intl.ListFormat(t,e),z[n]=i),i}(this.intl,t)}isEnglish(){return"en"===this.locale||"en-us"===this.locale.toLowerCase()||K(this.intl).locale.startsWith("en-us")}getWeekSettings(){return this.weekSettings?this.weekSettings:qt()?function(t){let e=J.get(t);if(!e){const n=new Intl.Locale(t);e="getWeekInfo"in n?n.getWeekInfo():n.weekInfo,"minimalDays"in e||(e={...nt,...e}),J.set(t,e)}return e}(this.locale):nt}getStartOfWeek(){return this.getWeekSettings().firstDay}getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays}getWeekendDays(){return this.getWeekSettings().weekend}equals(t){return this.locale===t.locale&&this.numberingSystem===t.numberingSystem&&this.outputCalendar===t.outputCalendar}toString(){return`Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`}}let rt=null;class ot extends F{static get utcInstance(){return null===rt&&(rt=new ot(0)),rt}static instance(t){return 0===t?ot.utcInstance:new ot(t)}static parseSpecifier(t){if(t){const e=t.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(e)return new ot(oe(e[1],e[2]))}return null}constructor(t){super(),this.fixed=t}get type(){return"fixed"}get name(){return 0===this.fixed?"UTC":`UTC${le(this.fixed,"narrow")}`}get ianaName(){return 0===this.fixed?"Etc/UTC":`Etc/GMT${le(-this.fixed,"narrow")}`}offsetName(){return this.name}formatOffset(t,e){return le(this.fixed,e)}get isUniversal(){return!0}offset(){return this.fixed}equals(t){return"fixed"===t.type&&t.fixed===this.fixed}get isValid(){return!0}}class st extends F{constructor(t){super(),this.zoneName=t}get type(){return"invalid"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(){return null}formatOffset(){return""}offset(){return NaN}equals(){return!1}get isValid(){return!1}}function at(t,e){if(jt(t)||null===t)return e;if(t instanceof F)return t;if("string"==typeof t){const n=t.toLowerCase();return"default"===n?e:"local"===n||"system"===n?R.instance:"utc"===n||"gmt"===n?ot.utcInstance:ot.parseSpecifier(n)||V.create(t)}return Rt(t)?ot.instance(t):"object"==typeof t&&"offset"in t&&"function"==typeof t.offset?t:new st(t)}const lt={arab:"[٠-٩]",arabext:"[۰-۹]",bali:"[᭐-᭙]",beng:"[০-৯]",deva:"[०-९]",fullwide:"[0-9]",gujr:"[૦-૯]",hanidec:"[〇|一|二|三|四|五|六|七|八|九]",khmr:"[០-៩]",knda:"[೦-೯]",laoo:"[໐-໙]",limb:"[᥆-᥏]",mlym:"[൦-൯]",mong:"[᠐-᠙]",mymr:"[၀-၉]",orya:"[୦-୯]",tamldec:"[௦-௯]",telu:"[౦-౯]",thai:"[๐-๙]",tibt:"[༠-༩]",latn:"\\d"},ct={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881]},ut=lt.hanidec.replace(/[\[|\]]/g,"").split("");const dt=new Map;function ht({numberingSystem:t},e=""){const n=t||"latn";let i=dt.get(n);void 0===i&&(i=new Map,dt.set(n,i));let r=i.get(e);return void 0===r&&(r=new RegExp(`${lt[n]}${e}`),i.set(e,r)),r}let pt,mt=()=>Date.now(),ft="system",gt=null,vt=null,yt=null,bt=60,_t=null;class wt{static get now(){return mt}static set now(t){mt=t}static set defaultZone(t){ft=t}static get defaultZone(){return at(ft,R.instance)}static get defaultLocale(){return gt}static set defaultLocale(t){gt=t}static get defaultNumberingSystem(){return vt}static set defaultNumberingSystem(t){vt=t}static get defaultOutputCalendar(){return yt}static set defaultOutputCalendar(t){yt=t}static get defaultWeekSettings(){return _t}static set defaultWeekSettings(t){_t=Bt(t)}static get twoDigitCutoffYear(){return bt}static set twoDigitCutoffYear(t){bt=t%100}static get throwOnInvalid(){return pt}static set throwOnInvalid(t){pt=t}static resetCaches(){it.resetCache(),V.resetCache(),bi.resetCache(),dt.clear()}}class kt{constructor(t,e){this.reason=t,this.explanation=e}toMessage(){return this.explanation?`${this.reason}: ${this.explanation}`:this.reason}}const Tt=[0,31,59,90,120,151,181,212,243,273,304,334],Et=[0,31,60,91,121,152,182,213,244,274,305,335];function St(t,e){return new kt("unit out of range",`you specified ${e} (of type ${typeof e}) as a ${t}, which is invalid`)}function xt(t,e,n){const i=new Date(Date.UTC(t,e-1,n));t<100&&t>=0&&i.setUTCFullYear(i.getUTCFullYear()-1900);const r=i.getUTCDay();return 0===r?7:r}function Dt(t,e,n){return n+(Jt(t)?Et:Tt)[e-1]}function Ot(t,e){const n=Jt(t)?Et:Tt,i=n.findIndex(t=>tne(i,e,n)?(l=i+1,c=1):l=i,{weekYear:l,weekNumber:c,weekday:a,...ce(t)}}function At(t,e=4,n=1){const{weekYear:i,weekNumber:r,weekday:o}=t,s=Lt(xt(i,1,e),n),a=Xt(i);let l,c=7*r+o-s-7+e;c<1?(l=i-1,c+=Xt(l)):c>a?(l=i+1,c-=Xt(i)):l=i;const{month:u,day:d}=Ot(l,c);return{year:l,month:u,day:d,...ce(t)}}function Mt(t){const{year:e,month:n,day:i}=t;return{year:e,ordinal:Dt(e,n,i),...ce(t)}}function It(t){const{year:e,ordinal:n}=t,{month:i,day:r}=Ot(e,n);return{year:e,month:i,day:r,...ce(t)}}function Nt(t,e){if(!jt(t.localWeekday)||!jt(t.localWeekNumber)||!jt(t.localWeekYear)){if(!jt(t.weekday)||!jt(t.weekNumber)||!jt(t.weekYear))throw new a("Cannot mix locale-based week fields with ISO-based week fields");return jt(t.localWeekday)||(t.weekday=t.localWeekday),jt(t.localWeekNumber)||(t.weekNumber=t.localWeekNumber),jt(t.localWeekYear)||(t.weekYear=t.localWeekYear),delete t.localWeekday,delete t.localWeekNumber,delete t.localWeekYear,{minDaysInFirstWeek:e.getMinDaysInFirstWeek(),startOfWeek:e.getStartOfWeek()}}return{minDaysInFirstWeek:4,startOfWeek:1}}function Pt(t){const e=$t(t.year),n=Wt(t.month,1,12),i=Wt(t.day,1,Qt(t.year,t.month));return e?n?!i&&St("day",t.day):St("month",t.month):St("year",t.year)}function Ft(t){const{hour:e,minute:n,second:i,millisecond:r}=t,o=Wt(e,0,23)||24===e&&0===n&&0===i&&0===r,s=Wt(n,0,59),a=Wt(i,0,59),l=Wt(r,0,999);return o?s?a?!l&&St("millisecond",r):St("second",i):St("minute",n):St("hour",e)}function jt(t){return void 0===t}function Rt(t){return"number"==typeof t}function $t(t){return"number"==typeof t&&t%1==0}function Ht(){try{return"undefined"!=typeof Intl&&!!Intl.RelativeTimeFormat}catch(t){return!1}}function qt(){try{return"undefined"!=typeof Intl&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype)}catch(t){return!1}}function Vt(t,e,n){if(0!==t.length)return t.reduce((t,i)=>{const r=[e(i),i];return t&&n(t[0],r[0])===t[0]?t:r},null)[1]}function zt(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function Bt(t){if(null==t)return null;if("object"!=typeof t)throw new c("Week settings must be an object");if(!Wt(t.firstDay,1,7)||!Wt(t.minimalDays,1,7)||!Array.isArray(t.weekend)||t.weekend.some(t=>!Wt(t,1,7)))throw new c("Invalid week settings");return{firstDay:t.firstDay,minimalDays:t.minimalDays,weekend:Array.from(t.weekend)}}function Wt(t,e,n){return $t(t)&&t>=e&&t<=n}function Ut(t,e=2){let n;return n=t<0?"-"+(""+-t).padStart(e,"0"):(""+t).padStart(e,"0"),n}function Yt(t){return jt(t)||null===t||""===t?void 0:parseInt(t,10)}function Zt(t){return jt(t)||null===t||""===t?void 0:parseFloat(t)}function Gt(t){if(!jt(t)&&null!==t&&""!==t){const e=1e3*parseFloat("0."+t);return Math.floor(e)}}function Kt(t,e,n="round"){const i=10**e;switch(n){case"expand":return t>0?Math.ceil(t*i)/i:Math.floor(t*i)/i;case"trunc":return Math.trunc(t*i)/i;case"round":return Math.round(t*i)/i;case"floor":return Math.floor(t*i)/i;case"ceil":return Math.ceil(t*i)/i;default:throw new RangeError(`Value rounding ${n} is out of range`)}}function Jt(t){return t%4==0&&(t%100!=0||t%400==0)}function Xt(t){return Jt(t)?366:365}function Qt(t,e){const n=function(t,e){return t-e*Math.floor(t/e)}(e-1,12)+1;return 2===n?Jt(t+(e-n)/12)?29:28:[31,null,31,30,31,30,31,31,30,31,30,31][n-1]}function te(t){let e=Date.UTC(t.year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond);return t.year<100&&t.year>=0&&(e=new Date(e),e.setUTCFullYear(t.year,t.month-1,t.day)),+e}function ee(t,e,n){return-Lt(xt(t,1,e),n)+e-1}function ne(t,e=4,n=1){const i=ee(t,e,n),r=ee(t+1,e,n);return(Xt(t)-i+r)/7}function ie(t){return t>99?t:t>wt.twoDigitCutoffYear?1900+t:2e3+t}function re(t,e,n,i=null){const r=new Date(t),o={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"};i&&(o.timeZone=i);const s={timeZoneName:e,...o},a=new Intl.DateTimeFormat(n,s).formatToParts(r).find(t=>"timezonename"===t.type.toLowerCase());return a?a.value:null}function oe(t,e){let n=parseInt(t,10);Number.isNaN(n)&&(n=0);const i=parseInt(e,10)||0;return 60*n+(n<0||Object.is(n,-0)?-i:i)}function se(t){const e=Number(t);if("boolean"==typeof t||""===t||!Number.isFinite(e))throw new c(`Invalid unit value ${t}`);return e}function ae(t,e){const n={};for(const i in t)if(zt(t,i)){const r=t[i];if(null==r)continue;n[e(i)]=se(r)}return n}function le(t,e){const n=Math.trunc(Math.abs(t/60)),i=Math.trunc(Math.abs(t%60)),r=t>=0?"+":"-";switch(e){case"short":return`${r}${Ut(n,2)}:${Ut(i,2)}`;case"narrow":return`${r}${n}${i>0?`:${i}`:""}`;case"techie":return`${r}${Ut(n,2)}${Ut(i,2)}`;default:throw new RangeError(`Value format ${e} is out of range for property format`)}}function ce(t){return function(t,e){return e.reduce((e,n)=>(e[n]=t[n],e),{})}(t,["hour","minute","second","millisecond"])}const ue=["January","February","March","April","May","June","July","August","September","October","November","December"],de=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],he=["J","F","M","A","M","J","J","A","S","O","N","D"];function pe(t){switch(t){case"narrow":return[...he];case"short":return[...de];case"long":return[...ue];case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null}}const me=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],fe=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],ge=["M","T","W","T","F","S","S"];function ve(t){switch(t){case"narrow":return[...ge];case"short":return[...fe];case"long":return[...me];case"numeric":return["1","2","3","4","5","6","7"];default:return null}}const ye=["AM","PM"],be=["Before Christ","Anno Domini"],_e=["BC","AD"],we=["B","A"];function ke(t){switch(t){case"narrow":return[...we];case"short":return[..._e];case"long":return[...be];default:return null}}function Te(t,e){let n="";for(const i of t)i.literal?n+=i.val:n+=e(i.val);return n}const Ee={D:m,DD:f,DDD:v,DDDD:y,t:b,tt:_,ttt:w,tttt:k,T:T,TT:E,TTT:S,TTTT:x,f:D,ff:L,fff:M,ffff:N,F:O,FF:C,FFF:I,FFFF:P};class Se{static create(t,e={}){return new Se(t,e)}static parseFormat(t){let e=null,n="",i=!1;const r=[];for(let o=0;o0||i)&&r.push({literal:i||/^\s+$/.test(n),val:""===n?"'":n}),e=null,n="",i=!i):i||s===e?n+=s:(n.length>0&&r.push({literal:/^\s+$/.test(n),val:n}),n=s,e=s)}return n.length>0&&r.push({literal:i||/^\s+$/.test(n),val:n}),r}static macroTokenToFormatOpts(t){return Ee[t]}constructor(t,e){this.opts=e,this.loc=t,this.systemLoc=null}formatWithSystemDefault(t,e){null===this.systemLoc&&(this.systemLoc=this.loc.redefaultToSystem());return this.systemLoc.dtFormatter(t,{...this.opts,...e}).format()}dtFormatter(t,e={}){return this.loc.dtFormatter(t,{...this.opts,...e})}formatDateTime(t,e){return this.dtFormatter(t,e).format()}formatDateTimeParts(t,e){return this.dtFormatter(t,e).formatToParts()}formatInterval(t,e){return this.dtFormatter(t.start,e).dtf.formatRange(t.start.toJSDate(),t.end.toJSDate())}resolvedOptions(t,e){return this.dtFormatter(t,e).resolvedOptions()}num(t,e=0,n=void 0){if(this.opts.forceSimple)return Ut(t,e);const i={...this.opts};return e>0&&(i.padTo=e),n&&(i.signDisplay=n),this.loc.numberFormatter(i).format(t)}formatDateTimeFromString(t,e){const n="en"===this.loc.listingMode(),i=this.loc.outputCalendar&&"gregory"!==this.loc.outputCalendar,r=(e,n)=>this.loc.extract(t,e,n),o=e=>t.isOffsetFixed&&0===t.offset&&e.allowZ?"Z":t.isValid?t.zone.formatOffset(t.ts,e.format):"",s=()=>n?function(t){return ye[t.hour<12?0:1]}(t):r({hour:"numeric",hourCycle:"h12"},"dayperiod"),a=(e,i)=>n?function(t,e){return pe(e)[t.month-1]}(t,e):r(i?{month:e}:{month:e,day:"numeric"},"month"),l=(e,i)=>n?function(t,e){return ve(e)[t.weekday-1]}(t,e):r(i?{weekday:e}:{weekday:e,month:"long",day:"numeric"},"weekday"),c=e=>{const n=Se.macroTokenToFormatOpts(e);return n?this.formatWithSystemDefault(t,n):e},u=e=>n?function(t,e){return ke(e)[t.year<0?0:1]}(t,e):r({era:e},"era");return Te(Se.parseFormat(e),e=>{switch(e){case"S":return this.num(t.millisecond);case"u":case"SSS":return this.num(t.millisecond,3);case"s":return this.num(t.second);case"ss":return this.num(t.second,2);case"uu":return this.num(Math.floor(t.millisecond/10),2);case"uuu":return this.num(Math.floor(t.millisecond/100));case"m":return this.num(t.minute);case"mm":return this.num(t.minute,2);case"h":return this.num(t.hour%12==0?12:t.hour%12);case"hh":return this.num(t.hour%12==0?12:t.hour%12,2);case"H":return this.num(t.hour);case"HH":return this.num(t.hour,2);case"Z":return o({format:"narrow",allowZ:this.opts.allowZ});case"ZZ":return o({format:"short",allowZ:this.opts.allowZ});case"ZZZ":return o({format:"techie",allowZ:this.opts.allowZ});case"ZZZZ":return t.zone.offsetName(t.ts,{format:"short",locale:this.loc.locale});case"ZZZZZ":return t.zone.offsetName(t.ts,{format:"long",locale:this.loc.locale});case"z":return t.zoneName;case"a":return s();case"d":return i?r({day:"numeric"},"day"):this.num(t.day);case"dd":return i?r({day:"2-digit"},"day"):this.num(t.day,2);case"c":case"E":return this.num(t.weekday);case"ccc":return l("short",!0);case"cccc":return l("long",!0);case"ccccc":return l("narrow",!0);case"EEE":return l("short",!1);case"EEEE":return l("long",!1);case"EEEEE":return l("narrow",!1);case"L":return i?r({month:"numeric",day:"numeric"},"month"):this.num(t.month);case"LL":return i?r({month:"2-digit",day:"numeric"},"month"):this.num(t.month,2);case"LLL":return a("short",!0);case"LLLL":return a("long",!0);case"LLLLL":return a("narrow",!0);case"M":return i?r({month:"numeric"},"month"):this.num(t.month);case"MM":return i?r({month:"2-digit"},"month"):this.num(t.month,2);case"MMM":return a("short",!1);case"MMMM":return a("long",!1);case"MMMMM":return a("narrow",!1);case"y":return i?r({year:"numeric"},"year"):this.num(t.year);case"yy":return i?r({year:"2-digit"},"year"):this.num(t.year.toString().slice(-2),2);case"yyyy":return i?r({year:"numeric"},"year"):this.num(t.year,4);case"yyyyyy":return i?r({year:"numeric"},"year"):this.num(t.year,6);case"G":return u("short");case"GG":return u("long");case"GGGGG":return u("narrow");case"kk":return this.num(t.weekYear.toString().slice(-2),2);case"kkkk":return this.num(t.weekYear,4);case"W":return this.num(t.weekNumber);case"WW":return this.num(t.weekNumber,2);case"n":return this.num(t.localWeekNumber);case"nn":return this.num(t.localWeekNumber,2);case"ii":return this.num(t.localWeekYear.toString().slice(-2),2);case"iiii":return this.num(t.localWeekYear,4);case"o":return this.num(t.ordinal);case"ooo":return this.num(t.ordinal,3);case"q":return this.num(t.quarter);case"qq":return this.num(t.quarter,2);case"X":return this.num(Math.floor(t.ts/1e3));case"x":return this.num(t.ts);default:return c(e)}})}formatDurationFromString(t,e){const n="negativeLargestOnly"===this.opts.signMode?-1:1,i=t=>{switch(t[0]){case"S":return"milliseconds";case"s":return"seconds";case"m":return"minutes";case"h":return"hours";case"d":return"days";case"w":return"weeks";case"M":return"months";case"y":return"years";default:return null}},r=Se.parseFormat(e),o=r.reduce((t,{literal:e,val:n})=>e?t:t.concat(n),[]),s=t.shiftTo(...o.map(i).filter(t=>t));return Te(r,((t,e)=>r=>{const o=i(r);if(o){const i=e.isNegativeDuration&&o!==e.largestUnit?n:1;let s;return s="negativeLargestOnly"===this.opts.signMode&&o!==e.largestUnit?"never":"all"===this.opts.signMode?"always":"auto",this.num(t.get(o)*i,r.length,s)}return r})(s,{isNegativeDuration:s<0,largestUnit:Object.keys(s.values)[0]}))}}const xe=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function De(...t){const e=t.reduce((t,e)=>t+e.source,"");return RegExp(`^${e}$`)}function Oe(...t){return e=>t.reduce(([t,n,i],r)=>{const[o,s,a]=r(e,i);return[{...t,...o},s||n,a]},[{},null,1]).slice(0,2)}function Le(t,...e){if(null==t)return[null,null];for(const[n,i]of e){const e=n.exec(t);if(e)return i(e)}return[null,null]}function Ce(...t){return(e,n)=>{const i={};let r;for(r=0;rvoid 0!==t&&(e||t&&u)?-t:t;return[{years:h(Zt(n)),months:h(Zt(i)),weeks:h(Zt(r)),days:h(Zt(o)),hours:h(Zt(s)),minutes:h(Zt(a)),seconds:h(Zt(l),"-0"===l),milliseconds:h(Gt(c),d)}]}const Ue={GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ye(t,e,n,i,r,o,s){const a={year:2===e.length?ie(Yt(e)):Yt(e),month:de.indexOf(n)+1,day:Yt(i),hour:Yt(r),minute:Yt(o)};return s&&(a.second=Yt(s)),t&&(a.weekday=t.length>3?me.indexOf(t)+1:fe.indexOf(t)+1),a}const Ze=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function Ge(t){const[,e,n,i,r,o,s,a,l,c,u,d]=t,h=Ye(e,r,i,n,o,s,a);let p;return p=l?Ue[l]:c?0:oe(u,d),[h,new ot(p)]}const Ke=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,Je=/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,Xe=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function Qe(t){const[,e,n,i,r,o,s,a]=t;return[Ye(e,r,i,n,o,s,a),ot.utcInstance]}function tn(t){const[,e,n,i,r,o,s,a]=t;return[Ye(e,a,n,i,r,o,s),ot.utcInstance]}const en=De(/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/,Ne),nn=De(/(\d{4})-?W(\d\d)(?:-?(\d))?/,Ne),rn=De(/(\d{4})-?(\d{3})/,Ne),on=De(Ie),sn=Oe(function(t,e){return[{year:$e(t,e),month:$e(t,e+1,1),day:$e(t,e+2,1)},null,e+3]},He,qe,Ve),an=Oe(Pe,He,qe,Ve),ln=Oe(Fe,He,qe,Ve),cn=Oe(He,qe,Ve);const un=Oe(He);const dn=De(/(\d{4})-(\d\d)-(\d\d)/,Re),hn=De(je),pn=Oe(He,qe,Ve);const mn="Invalid Duration",fn={weeks:{days:7,hours:168,minutes:10080,seconds:604800,milliseconds:6048e5},days:{hours:24,minutes:1440,seconds:86400,milliseconds:864e5},hours:{minutes:60,seconds:3600,milliseconds:36e5},minutes:{seconds:60,milliseconds:6e4},seconds:{milliseconds:1e3}},gn={years:{quarters:4,months:12,weeks:52,days:365,hours:8760,minutes:525600,seconds:31536e3,milliseconds:31536e6},quarters:{months:3,weeks:13,days:91,hours:2184,minutes:131040,seconds:7862400,milliseconds:78624e5},months:{weeks:4,days:30,hours:720,minutes:43200,seconds:2592e3,milliseconds:2592e6},...fn},vn=365.2425,yn=30.436875,bn={years:{quarters:4,months:12,weeks:52.1775,days:vn,hours:8765.82,minutes:525949.2,seconds:525949.2*60,milliseconds:525949.2*60*1e3},quarters:{months:3,weeks:13.044375,days:91.310625,hours:2191.455,minutes:131487.3,seconds:525949.2*60/4,milliseconds:7889237999.999999},months:{weeks:4.3481250000000005,days:yn,hours:730.485,minutes:43829.1,seconds:2629746,milliseconds:2629746e3},...fn},_n=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds"],wn=_n.slice(0).reverse();function kn(t,e,n=!1){const i={values:n?e.values:{...t.values,...e.values||{}},loc:t.loc.clone(e.loc),conversionAccuracy:e.conversionAccuracy||t.conversionAccuracy,matrix:e.matrix||t.matrix};return new xn(i)}function Tn(t,e){let n=e.milliseconds??0;for(const i of wn.slice(1))e[i]&&(n+=e[i]*t[i].milliseconds);return n}function En(t,e){const n=Tn(t,e)<0?-1:1;_n.reduceRight((i,r)=>{if(jt(e[r]))return i;if(i){const o=e[i]*n,s=t[r][i],a=Math.floor(o/s);e[r]+=a*n,e[i]-=a*s*n}return r},null),_n.reduce((n,i)=>{if(jt(e[i]))return n;if(n){const r=e[n]%1;e[n]-=r,e[i]+=r*t[n][i]}return i},null)}function Sn(t){const e={};for(const[n,i]of Object.entries(t))0!==i&&(e[n]=i);return e}class xn{constructor(t){const e="longterm"===t.conversionAccuracy||!1;let n=e?bn:gn;t.matrix&&(n=t.matrix),this.values=t.values,this.loc=t.loc||it.create(),this.conversionAccuracy=e?"longterm":"casual",this.invalid=t.invalid||null,this.matrix=n,this.isLuxonDuration=!0}static fromMillis(t,e){return xn.fromObject({milliseconds:t},e)}static fromObject(t,e={}){if(null==t||"object"!=typeof t)throw new c("Duration.fromObject: argument expected to be an object, got "+(null===t?"null":typeof t));return new xn({values:ae(t,xn.normalizeUnit),loc:it.fromObject(e),conversionAccuracy:e.conversionAccuracy,matrix:e.matrix})}static fromDurationLike(t){if(Rt(t))return xn.fromMillis(t);if(xn.isDuration(t))return t;if("object"==typeof t)return xn.fromObject(t);throw new c(`Unknown duration argument ${t} of type ${typeof t}`)}static fromISO(t,e){const[n]=function(t){return Le(t,[Be,We])}(t);return n?xn.fromObject(n,e):xn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static fromISOTime(t,e){const[n]=function(t){return Le(t,[ze,un])}(t);return n?xn.fromObject(n,e):xn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Duration is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new s(n);return new xn({invalid:n})}static normalizeUnit(t){const e={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds"}[t?t.toLowerCase():t];if(!e)throw new l(t);return e}static isDuration(t){return t&&t.isLuxonDuration||!1}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}toFormat(t,e={}){const n={...e,floor:!1!==e.round&&!1!==e.floor};return this.isValid?Se.create(this.loc,n).formatDurationFromString(this,t):mn}toHuman(t={}){if(!this.isValid)return mn;const e=!1!==t.showZeros,n=_n.map(n=>{const i=this.values[n];return jt(i)||0===i&&!e?null:this.loc.numberFormatter({style:"unit",unitDisplay:"long",...t,unit:n.slice(0,-1)}).format(i)}).filter(t=>t);return this.loc.listFormatter({type:"conjunction",style:t.listStyle||"narrow",...t}).format(n)}toObject(){return this.isValid?{...this.values}:{}}toISO(){if(!this.isValid)return null;let t="P";return 0!==this.years&&(t+=this.years+"Y"),0===this.months&&0===this.quarters||(t+=this.months+3*this.quarters+"M"),0!==this.weeks&&(t+=this.weeks+"W"),0!==this.days&&(t+=this.days+"D"),0===this.hours&&0===this.minutes&&0===this.seconds&&0===this.milliseconds||(t+="T"),0!==this.hours&&(t+=this.hours+"H"),0!==this.minutes&&(t+=this.minutes+"M"),0===this.seconds&&0===this.milliseconds||(t+=Kt(this.seconds+this.milliseconds/1e3,3)+"S"),"P"===t&&(t+="T0S"),t}toISOTime(t={}){if(!this.isValid)return null;const e=this.toMillis();if(e<0||e>=864e5)return null;t={suppressMilliseconds:!1,suppressSeconds:!1,includePrefix:!1,format:"extended",...t,includeOffset:!1};return bi.fromMillis(e,{zone:"UTC"}).toISOTime(t)}toJSON(){return this.toISO()}toString(){return this.toISO()}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Duration { values: ${JSON.stringify(this.values)} }`:`Duration { Invalid, reason: ${this.invalidReason} }`}toMillis(){return this.isValid?Tn(this.matrix,this.values):NaN}valueOf(){return this.toMillis()}plus(t){if(!this.isValid)return this;const e=xn.fromDurationLike(t),n={};for(const t of _n)(zt(e.values,t)||zt(this.values,t))&&(n[t]=e.get(t)+this.get(t));return kn(this,{values:n},!0)}minus(t){if(!this.isValid)return this;const e=xn.fromDurationLike(t);return this.plus(e.negate())}mapUnits(t){if(!this.isValid)return this;const e={};for(const n of Object.keys(this.values))e[n]=se(t(this.values[n],n));return kn(this,{values:e},!0)}get(t){return this[xn.normalizeUnit(t)]}set(t){if(!this.isValid)return this;return kn(this,{values:{...this.values,...ae(t,xn.normalizeUnit)}})}reconfigure({locale:t,numberingSystem:e,conversionAccuracy:n,matrix:i}={}){return kn(this,{loc:this.loc.clone({locale:t,numberingSystem:e}),matrix:i,conversionAccuracy:n})}as(t){return this.isValid?this.shiftTo(t).get(t):NaN}normalize(){if(!this.isValid)return this;const t=this.toObject();return En(this.matrix,t),kn(this,{values:t},!0)}rescale(){if(!this.isValid)return this;return kn(this,{values:Sn(this.normalize().shiftToAll().toObject())},!0)}shiftTo(...t){if(!this.isValid)return this;if(0===t.length)return this;t=t.map(t=>xn.normalizeUnit(t));const e={},n={},i=this.toObject();let r;for(const o of _n)if(t.indexOf(o)>=0){r=o;let t=0;for(const e in n)t+=this.matrix[e][o]*n[e],n[e]=0;Rt(i[o])&&(t+=i[o]);const s=Math.trunc(t);e[o]=s,n[o]=(1e3*t-1e3*s)/1e3}else Rt(i[o])&&(n[o]=i[o]);for(const t in n)0!==n[t]&&(e[r]+=t===r?n[t]:n[t]/this.matrix[r][t]);return En(this.matrix,e),kn(this,{values:e},!0)}shiftToAll(){return this.isValid?this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds"):this}negate(){if(!this.isValid)return this;const t={};for(const e of Object.keys(this.values))t[e]=0===this.values[e]?0:-this.values[e];return kn(this,{values:t},!0)}removeZeros(){if(!this.isValid)return this;return kn(this,{values:Sn(this.values)},!0)}get years(){return this.isValid?this.values.years||0:NaN}get quarters(){return this.isValid?this.values.quarters||0:NaN}get months(){return this.isValid?this.values.months||0:NaN}get weeks(){return this.isValid?this.values.weeks||0:NaN}get days(){return this.isValid?this.values.days||0:NaN}get hours(){return this.isValid?this.values.hours||0:NaN}get minutes(){return this.isValid?this.values.minutes||0:NaN}get seconds(){return this.isValid?this.values.seconds||0:NaN}get milliseconds(){return this.isValid?this.values.milliseconds||0:NaN}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}equals(t){if(!this.isValid||!t.isValid)return!1;if(!this.loc.equals(t.loc))return!1;function e(t,e){return void 0===t||0===t?void 0===e||0===e:t===e}for(const n of _n)if(!e(this.values[n],t.values[n]))return!1;return!0}}const Dn="Invalid Interval";class On{constructor(t){this.s=t.start,this.e=t.end,this.invalid=t.invalid||null,this.isLuxonInterval=!0}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Interval is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new o(n);return new On({invalid:n})}static fromDateTimes(t,e){const n=_i(t),i=_i(e),r=function(t,e){return t&&t.isValid?e&&e.isValid?et}isBefore(t){return!!this.isValid&&this.e<=t}contains(t){return!!this.isValid&&(this.s<=t&&this.e>t)}set({start:t,end:e}={}){return this.isValid?On.fromDateTimes(t||this.s,e||this.e):this}splitAt(...t){if(!this.isValid)return[];const e=t.map(_i).filter(t=>this.contains(t)).sort((t,e)=>t.toMillis()-e.toMillis()),n=[];let{s:i}=this,r=0;for(;i+this.e?this.e:t;n.push(On.fromDateTimes(i,o)),i=o,r+=1}return n}splitBy(t){const e=xn.fromDurationLike(t);if(!this.isValid||!e.isValid||0===e.as("milliseconds"))return[];let n,{s:i}=this,r=1;const o=[];for(;it*r));n=+t>+this.e?this.e:t,o.push(On.fromDateTimes(i,n)),i=n,r+=1}return o}divideEqually(t){return this.isValid?this.splitBy(this.length()/t).slice(0,t):[]}overlaps(t){return this.e>t.s&&this.s=t.e)}equals(t){return!(!this.isValid||!t.isValid)&&(this.s.equals(t.s)&&this.e.equals(t.e))}intersection(t){if(!this.isValid)return this;const e=this.s>t.s?this.s:t.s,n=this.e=n?null:On.fromDateTimes(e,n)}union(t){if(!this.isValid)return this;const e=this.st.e?this.e:t.e;return On.fromDateTimes(e,n)}static merge(t){const[e,n]=t.sort((t,e)=>t.s-e.s).reduce(([t,e],n)=>e?e.overlaps(n)||e.abutsStart(n)?[t,e.union(n)]:[t.concat([e]),n]:[t,n],[[],null]);return n&&e.push(n),e}static xor(t){let e=null,n=0;const i=[],r=t.map(t=>[{time:t.s,type:"s"},{time:t.e,type:"e"}]),o=Array.prototype.concat(...r).sort((t,e)=>t.time-e.time);for(const t of o)n+="s"===t.type?1:-1,1===n?e=t.time:(e&&+e!==+t.time&&i.push(On.fromDateTimes(e,t.time)),e=null);return On.merge(i)}difference(...t){return On.xor([this].concat(t)).map(t=>this.intersection(t)).filter(t=>t&&!t.isEmpty())}toString(){return this.isValid?`[${this.s.toISO()} – ${this.e.toISO()})`:Dn}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`:`Interval { Invalid, reason: ${this.invalidReason} }`}toLocaleString(t=m,e={}){return this.isValid?Se.create(this.s.loc.clone(e),t).formatInterval(this):Dn}toISO(t){return this.isValid?`${this.s.toISO(t)}/${this.e.toISO(t)}`:Dn}toISODate(){return this.isValid?`${this.s.toISODate()}/${this.e.toISODate()}`:Dn}toISOTime(t){return this.isValid?`${this.s.toISOTime(t)}/${this.e.toISOTime(t)}`:Dn}toFormat(t,{separator:e=" – "}={}){return this.isValid?`${this.s.toFormat(t)}${e}${this.e.toFormat(t)}`:Dn}toDuration(t,e){return this.isValid?this.e.diff(this.s,t,e):xn.invalid(this.invalidReason)}mapEndpoints(t){return On.fromDateTimes(t(this.s),t(this.e))}}class Ln{static hasDST(t=wt.defaultZone){const e=bi.now().setZone(t).set({month:12});return!t.isUniversal&&e.offset!==e.set({month:6}).offset}static isValidIANAZone(t){return V.isValidZone(t)}static normalizeZone(t){return at(t,wt.defaultZone)}static getStartOfWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getStartOfWeek()}static getMinimumDaysInFirstWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getMinDaysInFirstWeek()}static getWeekendWeekdays({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getWeekendDays().slice()}static months(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:r="gregory"}={}){return(i||it.create(e,n,r)).months(t)}static monthsFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:r="gregory"}={}){return(i||it.create(e,n,r)).months(t,!0)}static weekdays(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t)}static weekdaysFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t,!0)}static meridiems({locale:t=null}={}){return it.create(t).meridiems()}static eras(t="short",{locale:e=null}={}){return it.create(e,null,"gregory").eras(t)}static features(){return{relative:Ht(),localeWeek:qt()}}}function Cn(t,e){const n=t=>t.toUTC(0,{keepLocalTime:!0}).startOf("day").valueOf(),i=n(e)-n(t);return Math.floor(xn.fromMillis(i).as("days"))}function An(t,e,n,i){let[r,o,s,a]=function(t,e,n){const i=[["years",(t,e)=>e.year-t.year],["quarters",(t,e)=>e.quarter-t.quarter+4*(e.year-t.year)],["months",(t,e)=>e.month-t.month+12*(e.year-t.year)],["weeks",(t,e)=>{const n=Cn(t,e);return(n-n%7)/7}],["days",Cn]],r={},o=t;let s,a;for(const[l,c]of i)n.indexOf(l)>=0&&(s=l,r[l]=c(t,e),a=o.plus(r),a>e?(r[l]--,(t=o.plus(r))>e&&(a=t,r[l]--,t=o.plus(r))):t=a);return[t,r,a,s]}(t,e,n);const l=e-r,c=n.filter(t=>["hours","minutes","seconds","milliseconds"].indexOf(t)>=0);0===c.length&&(s0?xn.fromMillis(l,i).shiftTo(...c).plus(u):u}function Mn(t,e=t=>t){return{regex:t,deser:([t])=>e(function(t){let e=parseInt(t,10);if(isNaN(e)){e="";for(let n=0;n=n&&i<=r&&(e+=i-n)}}return parseInt(e,10)}return e}(t))}}const In=`[ ${String.fromCharCode(160)}]`,Nn=new RegExp(In,"g");function Pn(t){return t.replace(/\./g,"\\.?").replace(Nn,In)}function Fn(t){return t.replace(/\./g,"").replace(Nn," ").toLowerCase()}function jn(t,e){return null===t?null:{regex:RegExp(t.map(Pn).join("|")),deser:([n])=>t.findIndex(t=>Fn(n)===Fn(t))+e}}function Rn(t,e){return{regex:t,deser:([,t,e])=>oe(t,e),groups:e}}function $n(t){return{regex:t,deser:([t])=>t}}const Hn={year:{"2-digit":"yy",numeric:"yyyyy"},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM"},day:{numeric:"d","2-digit":"dd"},weekday:{short:"EEE",long:"EEEE"},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh"},hour24:{numeric:"H","2-digit":"HH"},minute:{numeric:"m","2-digit":"mm"},second:{numeric:"s","2-digit":"ss"},timeZoneName:{long:"ZZZZZ",short:"ZZZ"}};let qn=null;function Vn(t,e){return Array.prototype.concat(...t.map(t=>function(t,e){if(t.literal)return t;const n=Wn(Se.macroTokenToFormatOpts(t.val),e);return null==n||n.includes(void 0)?t:n}(t,e)))}class zn{constructor(t,e){if(this.locale=t,this.format=e,this.tokens=Vn(Se.parseFormat(e),t),this.units=this.tokens.map(e=>function(t,e){const n=ht(e),i=ht(e,"{2}"),r=ht(e,"{3}"),o=ht(e,"{4}"),s=ht(e,"{6}"),a=ht(e,"{1,2}"),l=ht(e,"{1,3}"),c=ht(e,"{1,6}"),u=ht(e,"{1,9}"),d=ht(e,"{2,4}"),h=ht(e,"{4,6}"),p=t=>{return{regex:RegExp((e=t.val,e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"))),deser:([t])=>t,literal:!0};var e},m=(m=>{if(t.literal)return p(m);switch(m.val){case"G":return jn(e.eras("short"),0);case"GG":return jn(e.eras("long"),0);case"y":return Mn(c);case"yy":case"kk":return Mn(d,ie);case"yyyy":case"kkkk":return Mn(o);case"yyyyy":return Mn(h);case"yyyyyy":return Mn(s);case"M":case"L":case"d":case"H":case"h":case"m":case"q":case"s":case"W":return Mn(a);case"MM":case"LL":case"dd":case"HH":case"hh":case"mm":case"qq":case"ss":case"WW":return Mn(i);case"MMM":return jn(e.months("short",!0),1);case"MMMM":return jn(e.months("long",!0),1);case"LLL":return jn(e.months("short",!1),1);case"LLLL":return jn(e.months("long",!1),1);case"o":case"S":return Mn(l);case"ooo":case"SSS":return Mn(r);case"u":return $n(u);case"uu":return $n(a);case"uuu":case"E":case"c":return Mn(n);case"a":return jn(e.meridiems(),0);case"EEE":return jn(e.weekdays("short",!1),1);case"EEEE":return jn(e.weekdays("long",!1),1);case"ccc":return jn(e.weekdays("short",!0),1);case"cccc":return jn(e.weekdays("long",!0),1);case"Z":case"ZZ":return Rn(new RegExp(`([+-]${a.source})(?::(${i.source}))?`),2);case"ZZZ":return Rn(new RegExp(`([+-]${a.source})(${i.source})?`),2);case"z":return $n(/[a-z_+-/]{1,256}?/i);case" ":return $n(/[^\S\n\r]/);default:return p(m)}})(t)||{invalidReason:"missing Intl.DateTimeFormat.formatToParts support"};return m.token=t,m}(e,t)),this.disqualifyingUnit=this.units.find(t=>t.invalidReason),!this.disqualifyingUnit){const[t,e]=[`^${(n=this.units).map(t=>t.regex).reduce((t,e)=>`${t}(${e.source})`,"")}$`,n];this.regex=RegExp(t,"i"),this.handlers=e}var n}explainFromTokens(t){if(this.isValid){const[e,n]=function(t,e,n){const i=t.match(e);if(i){const t={};let e=1;for(const r in n)if(zt(n,r)){const o=n[r],s=o.groups?o.groups+1:1;!o.literal&&o.token&&(t[o.token.val[0]]=o.deser(i.slice(e,e+s))),e+=s}return[i,t]}return[i,{}]}(t,this.regex,this.handlers),[i,r,o]=n?function(t){let e,n=null;return jt(t.z)||(n=V.create(t.z)),jt(t.Z)||(n||(n=new ot(t.Z)),e=t.Z),jt(t.q)||(t.M=3*(t.q-1)+1),jt(t.h)||(t.h<12&&1===t.a?t.h+=12:12===t.h&&0===t.a&&(t.h=0)),0===t.G&&t.y&&(t.y=-t.y),jt(t.u)||(t.S=Gt(t.u)),[Object.keys(t).reduce((e,n)=>{const i=(t=>{switch(t){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null}})(n);return i&&(e[i]=t[n]),e},{}),n,e]}(n):[null,null,void 0];if(zt(n,"a")&&zt(n,"H"))throw new a("Can't include meridiem when specifying 24-hour format");return{input:t,tokens:this.tokens,regex:this.regex,rawMatches:e,matches:n,result:i,zone:r,specificOffset:o}}return{input:t,tokens:this.tokens,invalidReason:this.invalidReason}}get isValid(){return!this.disqualifyingUnit}get invalidReason(){return this.disqualifyingUnit?this.disqualifyingUnit.invalidReason:null}}function Bn(t,e,n){return new zn(t,n).explainFromTokens(e)}function Wn(t,e){if(!t)return null;const n=Se.create(e,t).dtFormatter((qn||(qn=bi.fromMillis(1555555555555)),qn)),i=n.formatToParts(),r=n.resolvedOptions();return i.map(e=>function(t,e,n){const{type:i,value:r}=t;if("literal"===i){const t=/^\s+$/.test(r);return{literal:!t,val:t?" ":r}}const o=e[i];let s=i;"hour"===i&&(s=null!=e.hour12?e.hour12?"hour12":"hour24":null!=e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle?"hour12":"hour24":n.hour12?"hour12":"hour24");let a=Hn[s];if("object"==typeof a&&(a=a[o]),a)return{literal:!1,val:a}}(e,t,r))}const Un="Invalid DateTime",Yn=864e13;function Zn(t){return new kt("unsupported zone",`the zone "${t.name}" is not supported`)}function Gn(t){return null===t.weekData&&(t.weekData=Ct(t.c)),t.weekData}function Kn(t){return null===t.localWeekData&&(t.localWeekData=Ct(t.c,t.loc.getMinDaysInFirstWeek(),t.loc.getStartOfWeek())),t.localWeekData}function Jn(t,e){const n={ts:t.ts,zone:t.zone,c:t.c,o:t.o,loc:t.loc,invalid:t.invalid};return new bi({...n,...e,old:n})}function Xn(t,e,n){let i=t-60*e*1e3;const r=n.offset(i);if(e===r)return[i,e];i-=60*(r-e)*1e3;const o=n.offset(i);return r===o?[i,r]:[t-60*Math.min(r,o)*1e3,Math.max(r,o)]}function Qn(t,e){const n=new Date(t+=60*e*1e3);return{year:n.getUTCFullYear(),month:n.getUTCMonth()+1,day:n.getUTCDate(),hour:n.getUTCHours(),minute:n.getUTCMinutes(),second:n.getUTCSeconds(),millisecond:n.getUTCMilliseconds()}}function ti(t,e,n){return Xn(te(t),e,n)}function ei(t,e){const n=t.o,i=t.c.year+Math.trunc(e.years),r=t.c.month+Math.trunc(e.months)+3*Math.trunc(e.quarters),o={...t.c,year:i,month:r,day:Math.min(t.c.day,Qt(i,r))+Math.trunc(e.days)+7*Math.trunc(e.weeks)},s=xn.fromObject({years:e.years-Math.trunc(e.years),quarters:e.quarters-Math.trunc(e.quarters),months:e.months-Math.trunc(e.months),weeks:e.weeks-Math.trunc(e.weeks),days:e.days-Math.trunc(e.days),hours:e.hours,minutes:e.minutes,seconds:e.seconds,milliseconds:e.milliseconds}).as("milliseconds"),a=te(o);let[l,c]=Xn(a,n,t.zone);return 0!==s&&(l+=s,c=t.zone.offset(l)),{ts:l,o:c}}function ni(t,e,n,i,r,o){const{setZone:s,zone:a}=n;if(t&&0!==Object.keys(t).length||e){const i=e||a,r=bi.fromObject(t,{...n,zone:i,specificOffset:o});return s?r:r.setZone(a)}return bi.invalid(new kt("unparsable",`the input "${r}" can't be parsed as ${i}`))}function ii(t,e,n=!0){return t.isValid?Se.create(it.create("en-US"),{allowZ:n,forceSimple:!0}).formatDateTimeFromString(t,e):null}function ri(t,e,n){const i=t.c.year>9999||t.c.year<0;let r="";if(i&&t.c.year>=0&&(r+="+"),r+=Ut(t.c.year,i?6:4),"year"===n)return r;if(e){if(r+="-",r+=Ut(t.c.month),"month"===n)return r;r+="-"}else if(r+=Ut(t.c.month),"month"===n)return r;return r+=Ut(t.c.day),r}function oi(t,e,n,i,r,o,s){let a=!n||0!==t.c.millisecond||0!==t.c.second,l="";switch(s){case"day":case"month":case"year":break;default:if(l+=Ut(t.c.hour),"hour"===s)break;if(e){if(l+=":",l+=Ut(t.c.minute),"minute"===s)break;a&&(l+=":",l+=Ut(t.c.second))}else{if(l+=Ut(t.c.minute),"minute"===s)break;a&&(l+=Ut(t.c.second))}if("second"===s)break;!a||i&&0===t.c.millisecond||(l+=".",l+=Ut(t.c.millisecond,3))}return r&&(t.isOffsetFixed&&0===t.offset&&!o?l+="Z":t.o<0?(l+="-",l+=Ut(Math.trunc(-t.o/60)),l+=":",l+=Ut(Math.trunc(-t.o%60))):(l+="+",l+=Ut(Math.trunc(t.o/60)),l+=":",l+=Ut(Math.trunc(t.o%60)))),o&&(l+="["+t.zone.ianaName+"]"),l}const si={month:1,day:1,hour:0,minute:0,second:0,millisecond:0},ai={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0},li={ordinal:1,hour:0,minute:0,second:0,millisecond:0},ci=["year","month","day","hour","minute","second","millisecond"],ui=["weekYear","weekNumber","weekday","hour","minute","second","millisecond"],di=["year","ordinal","hour","minute","second","millisecond"];function hi(t){const e={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal"}[t.toLowerCase()];if(!e)throw new l(t);return e}function pi(t){switch(t.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return hi(t)}}function mi(t,e){const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e);let r,o;if(jt(t.year))r=wt.now();else{for(const e of ci)jt(t[e])&&(t[e]=si[e]);const e=Pt(t)||Ft(t);if(e)return bi.invalid(e);const i=function(t){if(void 0===vi&&(vi=wt.now()),"iana"!==t.type)return t.offset(vi);const e=t.name;let n=yi.get(e);return void 0===n&&(n=t.offset(vi),yi.set(e,n)),n}(n);[r,o]=ti(t,i,n)}return new bi({ts:r,zone:n,loc:i,o:o})}function fi(t,e,n){const i=!!jt(n.round)||n.round,r=jt(n.rounding)?"trunc":n.rounding,o=(t,o)=>{t=Kt(t,i||n.calendary?0:2,n.calendary?"round":r);return e.loc.clone(n).relFormatter(n).format(t,o)},s=i=>n.calendary?e.hasSame(t,i)?0:e.startOf(i).diff(t.startOf(i),i).get(i):e.diff(t,i).get(i);if(n.unit)return o(s(n.unit),n.unit);for(const t of n.units){const e=s(t);if(Math.abs(e)>=1)return o(e,t)}return o(t>e?-0:0,n.units[n.units.length-1])}function gi(t){let e,n={};return t.length>0&&"object"==typeof t[t.length-1]?(n=t[t.length-1],e=Array.from(t).slice(0,t.length-1)):e=Array.from(t),[n,e]}let vi;const yi=new Map;class bi{constructor(t){const e=t.zone||wt.defaultZone;let n=t.invalid||(Number.isNaN(t.ts)?new kt("invalid input"):null)||(e.isValid?null:Zn(e));this.ts=jt(t.ts)?wt.now():t.ts;let i=null,r=null;if(!n){if(t.old&&t.old.ts===this.ts&&t.old.zone.equals(e))[i,r]=[t.old.c,t.old.o];else{const o=Rt(t.o)&&!t.old?t.o:e.offset(this.ts);i=Qn(this.ts,o),n=Number.isNaN(i.year)?new kt("invalid input"):null,i=n?null:i,r=n?null:o}}this._zone=e,this.loc=t.loc||it.create(),this.invalid=n,this.weekData=null,this.localWeekData=null,this.c=i,this.o=r,this.isLuxonDateTime=!0}static now(){return new bi({})}static local(){const[t,e]=gi(arguments),[n,i,r,o,s,a,l]=e;return mi({year:n,month:i,day:r,hour:o,minute:s,second:a,millisecond:l},t)}static utc(){const[t,e]=gi(arguments),[n,i,r,o,s,a,l]=e;return t.zone=ot.utcInstance,mi({year:n,month:i,day:r,hour:o,minute:s,second:a,millisecond:l},t)}static fromJSDate(t,e={}){const n=(i=t,"[object Date]"===Object.prototype.toString.call(i)?t.valueOf():NaN);var i;if(Number.isNaN(n))return bi.invalid("invalid input");const r=at(e.zone,wt.defaultZone);return r.isValid?new bi({ts:n,zone:r,loc:it.fromObject(e)}):bi.invalid(Zn(r))}static fromMillis(t,e={}){if(Rt(t))return t<-Yn||t>Yn?bi.invalid("Timestamp out of range"):new bi({ts:t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c(`fromMillis requires a numerical input, but received a ${typeof t} with value ${t}`)}static fromSeconds(t,e={}){if(Rt(t))return new bi({ts:1e3*t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c("fromSeconds requires a numerical input")}static fromObject(t,e={}){t=t||{};const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e),r=ae(t,pi),{minDaysInFirstWeek:o,startOfWeek:s}=Nt(r,i),l=wt.now(),c=jt(e.specificOffset)?n.offset(l):e.specificOffset,u=!jt(r.ordinal),d=!jt(r.year),h=!jt(r.month)||!jt(r.day),p=d||h,m=r.weekYear||r.weekNumber;if((p||u)&&m)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(h&&u)throw new a("Can't mix ordinal dates with month/day");const f=m||r.weekday&&!p;let g,v,y=Qn(l,c);f?(g=ui,v=ai,y=Ct(y,o,s)):u?(g=di,v=li,y=Mt(y)):(g=ci,v=si);let b=!1;for(const t of g){jt(r[t])?r[t]=b?v[t]:y[t]:b=!0}const _=f?function(t,e=4,n=1){const i=$t(t.weekYear),r=Wt(t.weekNumber,1,ne(t.weekYear,e,n)),o=Wt(t.weekday,1,7);return i?r?!o&&St("weekday",t.weekday):St("week",t.weekNumber):St("weekYear",t.weekYear)}(r,o,s):u?function(t){const e=$t(t.year),n=Wt(t.ordinal,1,Xt(t.year));return e?!n&&St("ordinal",t.ordinal):St("year",t.year)}(r):Pt(r),w=_||Ft(r);if(w)return bi.invalid(w);const k=f?At(r,o,s):u?It(r):r,[T,E]=ti(k,c,n),S=new bi({ts:T,zone:n,o:E,loc:i});return r.weekday&&p&&t.weekday!==S.weekday?bi.invalid("mismatched weekday",`you can't specify both a weekday of ${r.weekday} and a date of ${S.toISO()}`):S.isValid?S:bi.invalid(S.invalid)}static fromISO(t,e={}){const[n,i]=function(t){return Le(t,[en,sn],[nn,an],[rn,ln],[on,cn])}(t);return ni(n,i,e,"ISO 8601",t)}static fromRFC2822(t,e={}){const[n,i]=function(t){return Le(function(t){return t.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim()}(t),[Ze,Ge])}(t);return ni(n,i,e,"RFC 2822",t)}static fromHTTP(t,e={}){const[n,i]=function(t){return Le(t,[Ke,Qe],[Je,Qe],[Xe,tn])}(t);return ni(n,i,e,"HTTP",e)}static fromFormat(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormat requires an input string and a format");const{locale:i=null,numberingSystem:r=null}=n,o=it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0}),[s,a,l,u]=function(t,e,n){const{result:i,zone:r,specificOffset:o,invalidReason:s}=Bn(t,e,n);return[i,r,o,s]}(o,t,e);return u?bi.invalid(u):ni(s,a,n,`format ${e}`,t,l)}static fromString(t,e,n={}){return bi.fromFormat(t,e,n)}static fromSQL(t,e={}){const[n,i]=function(t){return Le(t,[dn,sn],[hn,pn])}(t);return ni(n,i,e,"SQL",t)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the DateTime is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new r(n);return new bi({invalid:n})}static isDateTime(t){return t&&t.isLuxonDateTime||!1}static parseFormatForOpts(t,e={}){const n=Wn(t,it.fromObject(e));return n?n.map(t=>t?t.val:null).join(""):null}static expandFormat(t,e={}){return Vn(Se.parseFormat(t),it.fromObject(e)).map(t=>t.val).join("")}static resetCache(){vi=void 0,yi.clear()}get(t){return this[t]}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}get outputCalendar(){return this.isValid?this.loc.outputCalendar:null}get zone(){return this._zone}get zoneName(){return this.isValid?this.zone.name:null}get year(){return this.isValid?this.c.year:NaN}get quarter(){return this.isValid?Math.ceil(this.c.month/3):NaN}get month(){return this.isValid?this.c.month:NaN}get day(){return this.isValid?this.c.day:NaN}get hour(){return this.isValid?this.c.hour:NaN}get minute(){return this.isValid?this.c.minute:NaN}get second(){return this.isValid?this.c.second:NaN}get millisecond(){return this.isValid?this.c.millisecond:NaN}get weekYear(){return this.isValid?Gn(this).weekYear:NaN}get weekNumber(){return this.isValid?Gn(this).weekNumber:NaN}get weekday(){return this.isValid?Gn(this).weekday:NaN}get isWeekend(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday)}get localWeekday(){return this.isValid?Kn(this).weekday:NaN}get localWeekNumber(){return this.isValid?Kn(this).weekNumber:NaN}get localWeekYear(){return this.isValid?Kn(this).weekYear:NaN}get ordinal(){return this.isValid?Mt(this.c).ordinal:NaN}get monthShort(){return this.isValid?Ln.months("short",{locObj:this.loc})[this.month-1]:null}get monthLong(){return this.isValid?Ln.months("long",{locObj:this.loc})[this.month-1]:null}get weekdayShort(){return this.isValid?Ln.weekdays("short",{locObj:this.loc})[this.weekday-1]:null}get weekdayLong(){return this.isValid?Ln.weekdays("long",{locObj:this.loc})[this.weekday-1]:null}get offset(){return this.isValid?+this.o:NaN}get offsetNameShort(){return this.isValid?this.zone.offsetName(this.ts,{format:"short",locale:this.locale}):null}get offsetNameLong(){return this.isValid?this.zone.offsetName(this.ts,{format:"long",locale:this.locale}):null}get isOffsetFixed(){return this.isValid?this.zone.isUniversal:null}get isInDST(){return!this.isOffsetFixed&&(this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset)}getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed)return[this];const t=864e5,e=6e4,n=te(this.c),i=this.zone.offset(n-t),r=this.zone.offset(n+t),o=this.zone.offset(n-i*e),s=this.zone.offset(n-r*e);if(o===s)return[this];const a=n-o*e,l=n-s*e,c=Qn(a,o),u=Qn(l,s);return c.hour===u.hour&&c.minute===u.minute&&c.second===u.second&&c.millisecond===u.millisecond?[Jn(this,{ts:a}),Jn(this,{ts:l})]:[this]}get isInLeapYear(){return Jt(this.year)}get daysInMonth(){return Qt(this.year,this.month)}get daysInYear(){return this.isValid?Xt(this.year):NaN}get weeksInWeekYear(){return this.isValid?ne(this.weekYear):NaN}get weeksInLocalWeekYear(){return this.isValid?ne(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN}resolvedLocaleOptions(t={}){const{locale:e,numberingSystem:n,calendar:i}=Se.create(this.loc.clone(t),t).resolvedOptions(this);return{locale:e,numberingSystem:n,outputCalendar:i}}toUTC(t=0,e={}){return this.setZone(ot.instance(t),e)}toLocal(){return this.setZone(wt.defaultZone)}setZone(t,{keepLocalTime:e=!1,keepCalendarTime:n=!1}={}){if((t=at(t,wt.defaultZone)).equals(this.zone))return this;if(t.isValid){let i=this.ts;if(e||n){const e=t.offset(this.ts),n=this.toObject();[i]=ti(n,e,t)}return Jn(this,{ts:i,zone:t})}return bi.invalid(Zn(t))}reconfigure({locale:t,numberingSystem:e,outputCalendar:n}={}){return Jn(this,{loc:this.loc.clone({locale:t,numberingSystem:e,outputCalendar:n})})}setLocale(t){return this.reconfigure({locale:t})}set(t){if(!this.isValid)return this;const e=ae(t,pi),{minDaysInFirstWeek:n,startOfWeek:i}=Nt(e,this.loc),r=!jt(e.weekYear)||!jt(e.weekNumber)||!jt(e.weekday),o=!jt(e.ordinal),s=!jt(e.year),l=!jt(e.month)||!jt(e.day),c=s||l,u=e.weekYear||e.weekNumber;if((c||o)&&u)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(l&&o)throw new a("Can't mix ordinal dates with month/day");let d;r?d=At({...Ct(this.c,n,i),...e},n,i):jt(e.ordinal)?(d={...this.toObject(),...e},jt(e.day)&&(d.day=Math.min(Qt(d.year,d.month),d.day))):d=It({...Mt(this.c),...e});const[h,p]=ti(d,this.o,this.zone);return Jn(this,{ts:h,o:p})}plus(t){if(!this.isValid)return this;return Jn(this,ei(this,xn.fromDurationLike(t)))}minus(t){if(!this.isValid)return this;return Jn(this,ei(this,xn.fromDurationLike(t).negate()))}startOf(t,{useLocaleWeeks:e=!1}={}){if(!this.isValid)return this;const n={},i=xn.normalizeUnit(t);switch(i){case"years":n.month=1;case"quarters":case"months":n.day=1;case"weeks":case"days":n.hour=0;case"hours":n.minute=0;case"minutes":n.second=0;case"seconds":n.millisecond=0}if("weeks"===i)if(e){const t=this.loc.getStartOfWeek(),{weekday:e}=this;e=3&&(a+="T"),a+=oi(this,s,e,n,i,r,o),a}toISODate({format:t="extended",precision:e="day"}={}){return this.isValid?ri(this,"extended"===t,hi(e)):null}toISOWeekDate(){return ii(this,"kkkk-'W'WW-c")}toISOTime({suppressMilliseconds:t=!1,suppressSeconds:e=!1,includeOffset:n=!0,includePrefix:i=!1,extendedZone:r=!1,format:o="extended",precision:s="milliseconds"}={}){if(!this.isValid)return null;return s=hi(s),(i&&ci.indexOf(s)>=3?"T":"")+oi(this,"extended"===o,e,t,n,r,s)}toRFC2822(){return ii(this,"EEE, dd LLL yyyy HH:mm:ss ZZZ",!1)}toHTTP(){return ii(this.toUTC(),"EEE, dd LLL yyyy HH:mm:ss 'GMT'")}toSQLDate(){return this.isValid?ri(this,!0):null}toSQLTime({includeOffset:t=!0,includeZone:e=!1,includeOffsetSpace:n=!0}={}){let i="HH:mm:ss.SSS";return(e||t)&&(n&&(i+=" "),e?i+="z":t&&(i+="ZZ")),ii(this,i,!0)}toSQL(t={}){return this.isValid?`${this.toSQLDate()} ${this.toSQLTime(t)}`:null}toString(){return this.isValid?this.toISO():Un}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`:`DateTime { Invalid, reason: ${this.invalidReason} }`}valueOf(){return this.toMillis()}toMillis(){return this.isValid?this.ts:NaN}toSeconds(){return this.isValid?this.ts/1e3:NaN}toUnixInteger(){return this.isValid?Math.floor(this.ts/1e3):NaN}toJSON(){return this.toISO()}toBSON(){return this.toJSDate()}toObject(t={}){if(!this.isValid)return{};const e={...this.c};return t.includeConfig&&(e.outputCalendar=this.outputCalendar,e.numberingSystem=this.loc.numberingSystem,e.locale=this.loc.locale),e}toJSDate(){return new Date(this.isValid?this.ts:NaN)}diff(t,e="milliseconds",n={}){if(!this.isValid||!t.isValid)return xn.invalid("created by diffing an invalid DateTime");const i={locale:this.locale,numberingSystem:this.numberingSystem,...n},r=(a=e,Array.isArray(a)?a:[a]).map(xn.normalizeUnit),o=t.valueOf()>this.valueOf(),s=An(o?this:t,o?t:this,r,i);var a;return o?s.negate():s}diffNow(t="milliseconds",e={}){return this.diff(bi.now(),t,e)}until(t){return this.isValid?On.fromDateTimes(this,t):this}hasSame(t,e,n){if(!this.isValid)return!1;const i=t.valueOf(),r=this.setZone(t.zone,{keepLocalTime:!0});return r.startOf(e,n)<=i&&i<=r.endOf(e,n)}equals(t){return this.isValid&&t.isValid&&this.valueOf()===t.valueOf()&&this.zone.equals(t.zone)&&this.loc.equals(t.loc)}toRelative(t={}){if(!this.isValid)return null;const e=t.base||bi.fromObject({},{zone:this.zone}),n=t.padding?thist.valueOf(),Math.min)}static max(...t){if(!t.every(bi.isDateTime))throw new c("max requires all arguments be DateTimes");return Vt(t,t=>t.valueOf(),Math.max)}static fromFormatExplain(t,e,n={}){const{locale:i=null,numberingSystem:r=null}=n;return Bn(it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0}),t,e)}static fromStringExplain(t,e,n={}){return bi.fromFormatExplain(t,e,n)}static buildFormatParser(t,e={}){const{locale:n=null,numberingSystem:i=null}=e,r=it.fromOpts({locale:n,numberingSystem:i,defaultToEN:!0});return new zn(r,t)}static fromFormatParser(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormatParser requires an input string and a format parser");const{locale:i=null,numberingSystem:r=null}=n,o=it.fromOpts({locale:i,numberingSystem:r,defaultToEN:!0});if(!o.equals(e.locale))throw new c(`fromFormatParser called with a locale of ${o}, but the format parser was created for ${e.locale}`);const{result:s,zone:a,specificOffset:l,invalidReason:u}=e.explainFromTokens(t);return u?bi.invalid(u):ni(s,a,n,`format ${e.format}`,t,l)}static get DATE_SHORT(){return m}static get DATE_MED(){return f}static get DATE_MED_WITH_WEEKDAY(){return g}static get DATE_FULL(){return v}static get DATE_HUGE(){return y}static get TIME_SIMPLE(){return b}static get TIME_WITH_SECONDS(){return _}static get TIME_WITH_SHORT_OFFSET(){return w}static get TIME_WITH_LONG_OFFSET(){return k}static get TIME_24_SIMPLE(){return T}static get TIME_24_WITH_SECONDS(){return E}static get TIME_24_WITH_SHORT_OFFSET(){return S}static get TIME_24_WITH_LONG_OFFSET(){return x}static get DATETIME_SHORT(){return D}static get DATETIME_SHORT_WITH_SECONDS(){return O}static get DATETIME_MED(){return L}static get DATETIME_MED_WITH_SECONDS(){return C}static get DATETIME_MED_WITH_WEEKDAY(){return A}static get DATETIME_FULL(){return M}static get DATETIME_FULL_WITH_SECONDS(){return I}static get DATETIME_HUGE(){return N}static get DATETIME_HUGE_WITH_SECONDS(){return P}}function _i(t){if(bi.isDateTime(t))return t;if(t&&t.valueOf&&Rt(t.valueOf()))return bi.fromJSDate(t);if(t&&"object"==typeof t)return bi.fromObject(t);throw new c(`Unknown datetime argument: ${t}, of type ${typeof t}`)}}},function(t){var e;e=7368,t(t.s=e)}]); \ No newline at end of file diff --git a/public/build/entrypoints.json b/public/build/entrypoints.json index ad00286a..f31fab3f 100644 --- a/public/build/entrypoints.json +++ b/public/build/entrypoints.json @@ -3,7 +3,7 @@ "app": { "js": [ "/build/runtime.684e9f6d.js", - "/build/app.77b6dec9.js" + "/build/app.4f8430f7.js" ], "css": [ "/build/app.49955ea2.css" @@ -81,7 +81,7 @@ }, "integrity": { "/build/runtime.684e9f6d.js": "sha384-suKiEX2de4fdNqQzdYbUd6osp4AepD9FiMXl+1QdvgMW9dcQqUWQNQasf3KWzwLr", - "/build/app.77b6dec9.js": "sha384-qaaKjV9klY58pqcU0Ynu4jjnhO9kZK2kVQD1lcVS1nQs759cFYIRfXpTXmGYppei", + "/build/app.4f8430f7.js": "sha384-X029h9FgtC24+GvFSqlEVnKRrumwmpyWaD8nkFZlIYfDoV3/43Gnj5A4s88GopVD", "/build/app.49955ea2.css": "sha384-8ix/CKnR2d1mU3tMEFJPrOOPtQA2tdzHugEJMnODX+7my6dFwlworNdfZwrwuvz5", "/build/app-rtl.88289026.js": "sha384-gOohic29TurHJC5g2lJbDPbhnbrpZv8dCzS2QrUOHToldu1kIhhV+nwIhrIcvh2M", "/build/app-rtl.e8e3029e.css": "sha384-21kGyBRbajbE/gt4g8ej+clQSGAvYx1BMmiUMRTAE3ZVpMb5bvO/kVRcdKuV97J5", diff --git a/public/build/manifest.json b/public/build/manifest.json index 4a88121d..f66a3094 100644 --- a/public/build/manifest.json +++ b/public/build/manifest.json @@ -1,6 +1,6 @@ { "build/app.css": "/build/app.49955ea2.css", - "build/app.js": "/build/app.77b6dec9.js", + "build/app.js": "/build/app.4f8430f7.js", "build/app-rtl.css": "/build/app-rtl.e8e3029e.css", "build/app-rtl.js": "/build/app-rtl.88289026.js", "build/export-pdf.css": "/build/export-pdf.d8a6c23b.css", diff --git a/public/wizard/completed.svg b/public/wizard/completed.svg new file mode 100644 index 00000000..d6d99bf0 --- /dev/null +++ b/public/wizard/completed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/wizard/done.png b/public/wizard/done.png deleted file mode 100644 index 3f80b436..00000000 Binary files a/public/wizard/done.png and /dev/null differ diff --git a/public/wizard/time-management.png b/public/wizard/time-management.png deleted file mode 100644 index f1f79624..00000000 Binary files a/public/wizard/time-management.png and /dev/null differ diff --git a/public/wizard/time-management.svg b/public/wizard/time-management.svg new file mode 100644 index 00000000..ed8a962a --- /dev/null +++ b/public/wizard/time-management.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/API/ActivityController.php b/src/API/ActivityController.php index 84024e37..7949d032 100644 --- a/src/API/ActivityController.php +++ b/src/API/ActivityController.php @@ -18,6 +18,7 @@ use App\Repository\ActivityRateRepository; use App\Repository\ActivityRepository; use App\Repository\ProjectRepository; use App\Repository\Query\ActivityQuery; +use App\User\TeamService; use App\Utils\SearchTerm; use FOS\RestBundle\Controller\Annotations as Rest; use FOS\RestBundle\Request\ParamFetcherInterface; @@ -27,6 +28,7 @@ use OpenApi\Attributes as OA; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; @@ -308,4 +310,39 @@ final class ActivityController extends BaseApiController return $this->viewHandler->handle($view); } + + /** + * Create team for activity + * + * If a team with the activity's name already exists, it is reused. + * The current user is added as teamlead (if not already), and the activity is bound to the team. + */ + #[IsGranted('create_team')] + #[IsGranted('permissions', 'activity')] + #[OA\Post(description: 'Creates (or reuses) a default team named after the activity, makes the current user a teamlead, and binds the activity to that team. Calling this multiple times is safe and will not create duplicate teams or bindings.', responses: [new OA\Response(response: 200, description: 'Returns the team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] + #[OA\Parameter(name: 'id', description: 'The activity to create a default team for', in: 'path', required: true)] + #[Route(path: '/{id}/team', name: 'post_activity_team', requirements: ['id' => '\d+'], methods: ['POST'])] + public function postDefaultTeamAction(Activity $activity, TeamService $teamService): Response + { + $name = $activity->getName(); + if ($name === null || $name === '') { + throw new BadRequestHttpException('Cannot create default team for activity with empty name: ' . $activity->getId()); + } + + $team = $teamService->findTeamByName($name); + + if ($team === null) { + $team = $teamService->createNewTeam($name); + } + + $team->addTeamlead($this->getUser()); + $team->addActivity($activity); + + $teamService->saveTeam($team); + + $view = new View($team, Response::HTTP_OK); + $view->getContext()->setGroups(TeamController::GROUPS_ENTITY); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/CustomerController.php b/src/API/CustomerController.php index 30e56f96..d25d87b7 100644 --- a/src/API/CustomerController.php +++ b/src/API/CustomerController.php @@ -20,6 +20,7 @@ use App\Form\API\CustomerRateApiForm; use App\Repository\CustomerRateRepository; use App\Repository\CustomerRepository; use App\Repository\Query\CustomerQuery; +use App\User\TeamService; use App\Utils\SearchTerm; use FOS\RestBundle\Controller\Annotations as Rest; use FOS\RestBundle\Request\ParamFetcherInterface; @@ -29,6 +30,7 @@ use OpenApi\Attributes as OA; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; @@ -401,4 +403,39 @@ final class CustomerController extends BaseApiController return $this->viewHandler->handle(new View(null, Response::HTTP_NO_CONTENT)); } + + /** + * Create team for customer + * + * If a team with the customer's name already exists, it is reused. + * The current user is added as teamlead (if not already), and the customer is bound to the team. + */ + #[IsGranted('create_team')] + #[IsGranted('permissions', 'customer')] + #[OA\Post(description: 'Creates (or reuses) a default team named after the customer, makes the current user a teamlead, and binds the customer to that team. Calling this multiple times is safe and will not create duplicate teams or bindings.', responses: [new OA\Response(response: 200, description: 'Returns the team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] + #[OA\Parameter(name: 'id', description: 'The customer to create a default team for', in: 'path', required: true)] + #[Route(path: '/{id}/team', name: 'post_customer_team', requirements: ['id' => '\d+'], methods: ['POST'])] + public function postDefaultTeamAction(Customer $customer, TeamService $teamService): Response + { + $name = $customer->getName(); + if ($name === null || $name === '') { + throw new BadRequestHttpException('Cannot create default team for customer with empty name: ' . $customer->getId()); + } + + $team = $teamService->findTeamByName($name); + + if ($team === null) { + $team = $teamService->createNewTeam($name); + } + + $team->addTeamlead($this->getUser()); + $team->addCustomer($customer); + + $teamService->saveTeam($team); + + $view = new View($team, Response::HTTP_OK); + $view->getContext()->setGroups(TeamController::GROUPS_ENTITY); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/ProjectController.php b/src/API/ProjectController.php index 0c687dd6..43b2993e 100644 --- a/src/API/ProjectController.php +++ b/src/API/ProjectController.php @@ -21,6 +21,7 @@ use App\Repository\CustomerRepository; use App\Repository\ProjectRateRepository; use App\Repository\ProjectRepository; use App\Repository\Query\ProjectQuery; +use App\User\TeamService; use App\Utils\SearchTerm; use FOS\RestBundle\Controller\Annotations as Rest; use FOS\RestBundle\Request\ParamFetcherInterface; @@ -30,6 +31,7 @@ use OpenApi\Attributes as OA; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; use Symfony\Component\Validator\Constraints; @@ -457,4 +459,39 @@ final class ProjectController extends BaseApiController return $this->viewHandler->handle(new View(null, Response::HTTP_NO_CONTENT)); } + + /** + * Create team for project + * + * If a team with the project's name already exists, it is reused. + * The current user is added as teamlead (if not already), and the project is bound to the team. + */ + #[IsGranted('create_team')] + #[IsGranted('permissions', 'project')] + #[OA\Post(description: 'Creates (or reuses) a default team named after the project, makes the current user a teamlead, and binds the project to that team. Calling this multiple times is safe and will not create duplicate teams or bindings.', responses: [new OA\Response(response: 200, description: 'Returns the team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] + #[OA\Parameter(name: 'id', description: 'The project to create a default team for', in: 'path', required: true)] + #[Route(path: '/{id}/team', name: 'post_project_team', requirements: ['id' => '\d+'], methods: ['POST'])] + public function postDefaultTeamAction(Project $project, TeamService $teamService): Response + { + $name = $project->getName(); + if ($name === null || $name === '') { + throw new BadRequestHttpException('Cannot create default team for project with empty name: ' . $project->getId()); + } + + $team = $teamService->findTeamByName($name); + + if ($team === null) { + $team = $teamService->createNewTeam($name); + } + + $team->addTeamlead($this->getUser()); + $team->addProject($project); + + $teamService->saveTeam($team); + + $view = new View($team, Response::HTTP_OK); + $view->getContext()->setGroups(TeamController::GROUPS_ENTITY); + + return $this->viewHandler->handle($view); + } } diff --git a/src/API/TeamController.php b/src/API/TeamController.php index b9380d90..e1445afa 100644 --- a/src/API/TeamController.php +++ b/src/API/TeamController.php @@ -170,6 +170,7 @@ final class TeamController extends BaseApiController * Add team member */ #[IsGranted('edit', 'team')] + #[IsGranted('access_user', 'member')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new user to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team which will receive the new member', required: true)] #[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to add (User ID)', required: true)] @@ -224,6 +225,7 @@ final class TeamController extends BaseApiController * The team is granted access to the customer. */ #[IsGranted('edit', 'team')] + #[IsGranted('view', 'customer')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the team including the customer', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to grant acecess to (Customer ID)', required: true)] @@ -274,6 +276,7 @@ final class TeamController extends BaseApiController * The team is granted access to the project. */ #[IsGranted('edit', 'team')] + #[IsGranted('view', 'project')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the team including the project', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to grant acecess to (Project ID)', required: true)] @@ -324,6 +327,7 @@ final class TeamController extends BaseApiController * The team is granted access to the activity. */ #[IsGranted('edit', 'team')] + #[IsGranted('view', 'activity')] #[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the team including the activity', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])] #[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)] #[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to grant acecess to (Activity ID)', required: true)] diff --git a/src/API/TimesheetController.php b/src/API/TimesheetController.php index 6ea46238..397f34d3 100644 --- a/src/API/TimesheetController.php +++ b/src/API/TimesheetController.php @@ -429,16 +429,11 @@ final class TimesheetController extends BaseApiController /** * Stop active timesheet - * - * This route is available via GET and PATCH, as users over and over again run into errors when stopping. - * Likely caused by a slow JS engine and a fast-click after page reload. */ #[IsGranted('stop', 'timesheet')] #[OA\Response(response: 200, description: 'Stops an active timesheet and returns it afterwards.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet ID to stop', required: true)] - #[Route(methods: ['GET'], path: '/{id}/stop', name: 'stop_timesheet_get', requirements: ['id' => '\d+'])] #[Route(methods: ['PATCH'], path: '/{id}/stop', name: 'stop_timesheet', requirements: ['id' => '\d+'])] - #[OA\Get(x: ['internal' => true])] public function stopAction(Timesheet $timesheet): Response { $this->service->stopTimesheet($timesheet); @@ -457,8 +452,6 @@ final class TimesheetController extends BaseApiController #[IsGranted('start', 'timesheet')] #[OA\Response(response: 200, description: 'Restart a timesheet for the same customer, project, activity combination. The current user will be the owner of the new record. Kimai tries to stop running records, which is expected to fail depending on the configured rules. Data will be copied from the original record if requested.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))] #[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet ID to restart', required: true)] - #[OA\Get(x: ['internal' => true])] - #[Route(methods: ['GET'], path: '/{id}/restart', name: 'restart_timesheet_get', requirements: ['id' => '\d+'])] #[Route(methods: ['PATCH'], path: '/{id}/restart', name: 'restart_timesheet', requirements: ['id' => '\d+'])] #[Rest\RequestParam(name: 'copy', requirements: 'all', strict: true, nullable: true, description: 'Whether data should be copied to the new entry. Allowed values: all (default: nothing is copied)')] #[Rest\RequestParam(name: 'begin', requirements: [new Constraints\DateTime(format: 'Y-m-d\TH:i:s')], strict: true, nullable: true, description: 'Changes the restart date to the given one (default: now)')] diff --git a/src/Constants.php b/src/Constants.php index 7f02fb74..6c5eca02 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -17,11 +17,11 @@ final class Constants /** * The current release version */ - public const VERSION = '2.57.0'; + public const VERSION = '2.58.0'; /** * The current release: major * 10000 + minor * 100 + patch */ - public const VERSION_ID = 25700; + public const VERSION_ID = 25800; /** * The software name */ diff --git a/src/Controller/ActivityController.php b/src/Controller/ActivityController.php index 0ab975d9..7b706f4f 100644 --- a/src/Controller/ActivityController.php +++ b/src/Controller/ActivityController.php @@ -31,7 +31,6 @@ use App\Repository\Query\ActivityQuery; use App\Repository\Query\TeamQuery; use App\Repository\Query\TimesheetQuery; use App\Repository\TeamRepository; -use App\User\TeamService; use App\Utils\DataTable; use App\Utils\PageSetup; use Exception; @@ -40,7 +39,6 @@ use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; @@ -306,34 +304,6 @@ final class ActivityController extends AbstractController ]); } - #[Route(path: '/{id}/create_team', name: 'activity_team_create', methods: ['GET'])] - #[IsGranted('create_team')] - #[IsGranted('permissions', 'activity')] - public function createDefaultTeamAction(Activity $activity, TeamService $teamService): Response - { - $name = $activity->getName(); - if ($name === null) { - throw new BadRequestHttpException('Cannot create default team for activity with empty name: ' . $activity->getId()); - } - - $defaultTeam = $teamService->findTeamByName($name); - - if (null === $defaultTeam) { - $defaultTeam = $teamService->createNewTeam($name); - } - - $defaultTeam->addTeamlead($this->getUser()); - $defaultTeam->addActivity($activity); - - try { - $teamService->saveTeam($defaultTeam); - } catch (Exception $ex) { - $this->flashUpdateException($ex); - } - - return $this->redirectToRoute('activity_details', ['id' => $activity->getId()]); - } - #[Route(path: '/{id}/edit', name: 'admin_activity_edit', methods: ['GET', 'POST'])] #[IsGranted('edit', 'activity')] public function editAction(Activity $activity, Request $request, ActivityService $activityService, SystemConfiguration $configuration): Response diff --git a/src/Controller/CustomerController.php b/src/Controller/CustomerController.php index ebacc954..fea751e4 100644 --- a/src/Controller/CustomerController.php +++ b/src/Controller/CustomerController.php @@ -34,7 +34,6 @@ use App\Repository\Query\TeamQuery; use App\Repository\Query\TimesheetQuery; use App\Repository\Query\VisibilityInterface; use App\Repository\TeamRepository; -use App\User\TeamService; use App\Utils\DataTable; use App\Utils\PageSetup; use Psr\EventDispatcher\EventDispatcherInterface; @@ -42,7 +41,6 @@ use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; @@ -188,34 +186,6 @@ final class CustomerController extends AbstractController return $this->redirectToRoute('customer_details', ['id' => $customer->getId()]); } - #[Route(path: '/{id}/create_team', name: 'customer_team_create', methods: ['GET'])] - #[IsGranted('create_team')] - #[IsGranted('permissions', 'customer')] - public function createDefaultTeamAction(Customer $customer, TeamService $teamService): Response - { - $name = $customer->getName(); - if ($name === null) { - throw new BadRequestHttpException('Cannot create default team for customer with empty name: ' . $customer->getId()); - } - - $defaultTeam = $teamService->findTeamByName($name); - - if (null === $defaultTeam) { - $defaultTeam = $teamService->createNewTeam($name); - } - - $defaultTeam->addTeamlead($this->getUser()); - $defaultTeam->addCustomer($customer); - - try { - $teamService->saveTeam($defaultTeam); - } catch (\Exception $ex) { - $this->flashUpdateException($ex); - } - - return $this->redirectToRoute('customer_details', ['id' => $customer->getId()]); - } - #[Route(path: '/{id}/projects/{page}', defaults: ['page' => 1], name: 'customer_projects', methods: ['GET', 'POST'])] #[IsGranted('view', 'customer')] public function projectsAction(Customer $customer, int $page, ProjectRepository $projectRepository): Response diff --git a/src/Controller/DoctorController.php b/src/Controller/DoctorController.php index ecd8a653..08219223 100644 --- a/src/Controller/DoctorController.php +++ b/src/Controller/DoctorController.php @@ -32,6 +32,7 @@ final class DoctorController extends AbstractController public const DIRECTORIES_WRITABLE = [ 'var/cache/', 'var/log/', + 'var/packages/', ]; public function __construct(private string $projectDirectory, private string $kernelEnvironment, private FileHelper $fileHelper, private CacheInterface $cache) diff --git a/src/Controller/ExportController.php b/src/Controller/ExportController.php index 2c8d98bb..474ab306 100644 --- a/src/Controller/ExportController.php +++ b/src/Controller/ExportController.php @@ -208,12 +208,14 @@ final class ExportController extends AbstractController } #[Route(path: '/template-create', name: 'export_template_create', methods: ['GET', 'POST'])] + #[IsGranted('create_export_template')] public function createExportTemplate(Request $request, ExportTemplateRepository $repository): Response { return $this->editExportForm($this->generateUrl('export_template_create'), $request, $repository, new ExportTemplate()); } #[Route(path: '/template-edit/{exportTemplate}', name: 'export_template_edit', methods: ['GET', 'POST'])] + #[IsGranted('create_export_template')] public function editExportTemplate(ExportTemplate $exportTemplate, Request $request, ExportTemplateRepository $repository): Response { return $this->editExportForm($this->generateUrl('export_template_edit', ['exportTemplate' => $exportTemplate->getId()]), $request, $repository, $exportTemplate); diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index 1334a356..0c40a755 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -37,7 +37,6 @@ use App\Repository\Query\TeamQuery; use App\Repository\Query\TimesheetQuery; use App\Repository\Query\VisibilityInterface; use App\Repository\TeamRepository; -use App\User\TeamService; use App\Utils\Context; use App\Utils\DataTable; use App\Utils\PageSetup; @@ -46,7 +45,6 @@ use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -219,34 +217,6 @@ final class ProjectController extends AbstractController return $this->redirectToRoute('project_details', ['id' => $project->getId()]); } - #[Route(path: '/{id}/create_team', name: 'project_team_create', methods: ['GET'])] - #[IsGranted('create_team')] - #[IsGranted('permissions', 'project')] - public function createDefaultTeamAction(Project $project, TeamService $teamService): Response - { - $name = $project->getName(); - if ($name === null) { - throw new BadRequestHttpException('Cannot create default team for project with empty name: ' . $project->getId()); - } - - $defaultTeam = $teamService->findTeamByName($name); - - if (null === $defaultTeam) { - $defaultTeam = $teamService->createNewTeam($name); - } - - $defaultTeam->addTeamlead($this->getUser()); - $defaultTeam->addProject($project); - - try { - $teamService->saveTeam($defaultTeam); - } catch (\Exception $ex) { - $this->flashUpdateException($ex); - } - - return $this->redirectToRoute('project_details', ['id' => $project->getId()]); - } - #[Route(path: '/{id}/activities/{page}', defaults: ['page' => 1], name: 'project_activities', methods: ['GET', 'POST'])] #[IsGranted('view', 'project')] public function activitiesAction(Project $project, int $page, ActivityRepository $activityRepository): Response diff --git a/src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php b/src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php index 9c69ae1c..a367dace 100644 --- a/src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php +++ b/src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php @@ -25,11 +25,11 @@ abstract class AbstractTimesheetSubscriber extends AbstractActionsSubscriber $timesheet = $payload['timesheet']; if ($timesheet->getId() !== null) { if ($timesheet->isRunning() && $this->isGranted('stop', $timesheet)) { - $event->addAction('stop', ['url' => $this->path('stop_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link dd-ts-stop', 'attr' => ['data-event' => 'kimai.timesheetStop kimai.timesheetUpdate', 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.stop.error', 'data-msg-success' => 'timesheet.stop.success']]); + $event->addAction('stop', ['url' => '#', 'class' => 'api-link dd-ts-stop', 'attr' => ['data-event' => 'kimai.timesheetStop kimai.timesheetUpdate', 'data-href' => $this->path('stop_timesheet', ['id' => $timesheet->getId()]), 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.stop.error', 'data-msg-success' => 'timesheet.stop.success']]); } if (!$timesheet->isRunning() && $this->isGranted('start', $timesheet)) { - $event->addAction('repeat', ['title' => 'repeat', 'url' => $this->path('restart_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link dd-ts-repeat', 'attr' => ['data-payload' => '{"copy": "all"}', 'data-event' => 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.start.error', 'data-msg-success' => 'timesheet.start.success']]); + $event->addAction('repeat', ['title' => 'repeat', 'url' => '#', 'class' => 'api-link dd-ts-repeat', 'attr' => ['data-payload' => '{"copy": "all"}', 'data-event' => 'kimai.timesheetStart kimai.timesheetUpdate', 'data-href' => $this->path('restart_timesheet', ['id' => $timesheet->getId()]), 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.start.error', 'data-msg-success' => 'timesheet.start.success']]); } if ($this->isGranted('edit', $timesheet)) { diff --git a/src/EventSubscriber/PasswordResetSubscriber.php b/src/EventSubscriber/PasswordResetSubscriber.php new file mode 100644 index 00000000..94aceee8 --- /dev/null +++ b/src/EventSubscriber/PasswordResetSubscriber.php @@ -0,0 +1,70 @@ + ['onKernelRequest', -20] + ]; + } + + public function onKernelRequest(RequestEvent $event): void + { + // ignore sub-requests + if (!$event->isMainRequest() || null === ($token = $this->storage->getToken())) { + return; + } + + $uri = $event->getRequest()->getRequestUri(); + + // never trigger password reset on API calls + // TODO 3.0 remove /register/ + if (str_starts_with($uri, '/api/') || stripos($uri, '/register/') !== false || stripos($uri, '/wizard/') !== false) { + return; + } + + $user = $token->getUser(); + + if (!($user instanceof User)) { + return; + } + + if (!$this->security->isGranted('IS_AUTHENTICATED_FULLY')) { + return; + } + + if (!$user->requiresPasswordReset()) { + return; + } + + $response = new RedirectResponse($this->urlGenerator->generate('wizard', ['wizard' => 'password'])); + $event->setResponse($response); + } +} diff --git a/src/EventSubscriber/RedirectToLocaleSubscriber.php b/src/EventSubscriber/RedirectToLocaleSubscriber.php index a792fede..8c1f4673 100644 --- a/src/EventSubscriber/RedirectToLocaleSubscriber.php +++ b/src/EventSubscriber/RedirectToLocaleSubscriber.php @@ -10,11 +10,13 @@ namespace App\EventSubscriber; use App\Configuration\LocaleService; +use App\Entity\User; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** * When visiting the homepage, this listener redirects the user to the most @@ -24,7 +26,8 @@ final class RedirectToLocaleSubscriber implements EventSubscriberInterface { public function __construct( private readonly UrlGeneratorInterface $urlGenerator, - private readonly LocaleService $localeService + private readonly LocaleService $localeService, + private readonly TokenStorageInterface $storage, ) { } @@ -32,7 +35,9 @@ final class RedirectToLocaleSubscriber implements EventSubscriberInterface public static function getSubscribedEvents(): array { return [ - KernelEvents::REQUEST => ['onKernelRequest'] + // the higher the priority (default: 0), the earlier it is executed + // runs on default priority to make sure we have the correct locale in the URL + KernelEvents::REQUEST => ['onKernelRequest', 0] ]; } @@ -52,15 +57,26 @@ final class RedirectToLocaleSubscriber implements EventSubscriberInterface return; } - $allLanguages = $this->localeService->getTranslatedLocales(); + $preferredLanguage = null; - // Add the default locale at the first position of the array, because getPreferredLanguage() - // returns the first element when no appropriate language is found - array_unshift($allLanguages, 'en'); + if (null !== ($token = $this->storage->getToken())) { + $user = $token->getUser(); + if ($user instanceof User) { + $preferredLanguage = $user->getLanguage(); + } + } - $preferredLanguage = $request->getPreferredLanguage(array_unique($allLanguages)); + if ($preferredLanguage === null){ + $allLanguages = $this->localeService->getTranslatedLocales(); - $response = new RedirectResponse($this->urlGenerator->generate('homepage', ['_locale' => $preferredLanguage])); + // Add the default locale at the first position of the array, because getPreferredLanguage() + // returns the first element when no appropriate language is found + array_unshift($allLanguages, 'en'); + + $preferredLanguage = $request->getPreferredLanguage(array_unique($allLanguages)); + } + + $response = new RedirectResponse($this->urlGenerator->generate('homepage', ['_locale' => $preferredLanguage ?? 'en'])); $event->setResponse($response); } } diff --git a/src/EventSubscriber/UserEnvironmentSubscriber.php b/src/EventSubscriber/UserEnvironmentSubscriber.php index f989b4bb..907baa5b 100644 --- a/src/EventSubscriber/UserEnvironmentSubscriber.php +++ b/src/EventSubscriber/UserEnvironmentSubscriber.php @@ -12,6 +12,7 @@ namespace App\EventSubscriber; use App\Entity\User; use App\Twig\LocaleFormatExtensions; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -19,6 +20,8 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; final class UserEnvironmentSubscriber implements EventSubscriberInterface { + private ?string $userLocale = null; + public function __construct( private readonly TokenStorageInterface $tokenStorage, private readonly AuthorizationCheckerInterface $auth, @@ -30,10 +33,30 @@ final class UserEnvironmentSubscriber implements EventSubscriberInterface public static function getSubscribedEvents(): array { return [ - KernelEvents::REQUEST => ['prepareEnvironment', -100], + // runs as first one in Kimai, to make sure we use the correct locales for rendering + KernelEvents::REQUEST => ['prepareEnvironment', -10], + // don't know why do we use -20 + KernelEvents::FINISH_REQUEST => ['restoreLocale', -20], ]; } + public function restoreLocale(FinishRequestEvent $event): void + { + if ($event->isMainRequest()) { + return; + } + + if ($this->userLocale === null) { + return; + } + + // LocaleSwitcher (called by LocaleAwareListener) overwrites \Locale::getDefault() with the URL + // locale during sub-requests. Restore both the PHP default and the Twig formatter locale to + // the user's formatting locale that was saved during the main request. + \Locale::setDefault($this->userLocale); + $this->localeFormatExtensions->setLocale($this->userLocale); + } + public function prepareEnvironment(RequestEvent $event): void { // ignore sub-requests @@ -55,6 +78,7 @@ final class UserEnvironmentSubscriber implements EventSubscriberInterface } // the locale is primarily used for formatting values, so we depend on the user locale if available + $this->userLocale = $locale; \Locale::setDefault($locale); $this->localeFormatExtensions->setLocale($locale); } diff --git a/src/EventSubscriber/WizardSubscriber.php b/src/EventSubscriber/WizardSubscriber.php index 6802d78f..6823b3ac 100644 --- a/src/EventSubscriber/WizardSubscriber.php +++ b/src/EventSubscriber/WizardSubscriber.php @@ -22,35 +22,31 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; class WizardSubscriber implements EventSubscriberInterface { public function __construct( - private UrlGeneratorInterface $urlGenerator, - private AuthorizationCheckerInterface $security, - private TokenStorageInterface $storage, - private SystemConfiguration $systemConfiguration + private readonly UrlGeneratorInterface $urlGenerator, + private readonly AuthorizationCheckerInterface $security, + private readonly TokenStorageInterface $storage, + private readonly SystemConfiguration $systemConfiguration ) { } public static function getSubscribedEvents(): array { return [ - KernelEvents::REQUEST => ['onKernelRequest'] + KernelEvents::REQUEST => ['onKernelRequest', -30] ]; } public function onKernelRequest(RequestEvent $event): void { - // ignore sub-requests - if (!$event->isMainRequest()) { - return; - } - - // ignore events like the toolbar where we do not have a token - if (null === ($token = $this->storage->getToken())) { + // ignore sub-requests and un-authenticated events + if (!$event->isMainRequest() || null === ($token = $this->storage->getToken())) { return; } $uri = $event->getRequest()->getRequestUri(); - // never require 2FA on API calls + // never trigger wizard on API calls + // TODO 3.0 remove /register/ if (str_starts_with($uri, '/api/') || stripos($uri, '/register/') !== false || stripos($uri, '/wizard/') !== false) { return; } @@ -65,11 +61,6 @@ class WizardSubscriber implements EventSubscriberInterface return; } - if ($user->requiresPasswordReset()) { - $response = new RedirectResponse($this->urlGenerator->generate('wizard', ['wizard' => 'password'])); - $event->setResponse($response); - } - if ($user->isRegularUserOnly() && !$this->systemConfiguration->isUserWizardActive()) { return; } diff --git a/src/Pdf/MPdfConverter.php b/src/Pdf/MPdfConverter.php index b0ffdb95..75a89794 100644 --- a/src/Pdf/MPdfConverter.php +++ b/src/Pdf/MPdfConverter.php @@ -13,6 +13,8 @@ use App\Constants; use App\Utils\FileHelper; use Mpdf\Config\ConfigVariables; use Mpdf\Config\FontVariables; +use Mpdf\Container\SimpleContainer; +use Mpdf\Http\ClientInterface; use Mpdf\Mpdf; use Mpdf\Output\Destination; @@ -20,7 +22,8 @@ final class MPdfConverter implements HtmlToPdfConverter { public function __construct( private readonly FileHelper $fileHelper, - private readonly string $cacheDirectory + private readonly string $cacheDirectory, + private readonly ?ClientInterface $httpClient = null, ) { } @@ -116,7 +119,17 @@ final class MPdfConverter implements HtmlToPdfConverter unset($options['additional_xmp_rdf']); } - $mpdf = new Mpdf($options); + // Inject a safe HTTP client into mPDF (via its service container) so + // remote resources referenced from Twig templates — typically `` for company logos — cannot be abused to probe private + // networks. The configured Symfony client is decorated with + // NoPrivateNetworkHttpClient at the service-container level. + // @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + $container = $this->httpClient !== null + ? new SimpleContainer(['httpClient' => $this->httpClient]) + : null; + + $mpdf = new Mpdf($options, $container); $mpdf->creator = Constants::SOFTWARE; if (\count($associatedFiles) > 0) { diff --git a/src/Pdf/SafeRemoteContentClient.php b/src/Pdf/SafeRemoteContentClient.php new file mode 100644 index 00000000..b90b3945 --- /dev/null +++ b/src/Pdf/SafeRemoteContentClient.php @@ -0,0 +1,76 @@ +` references in custom Twig invoice templates. + * + * Blocked requests are translated to a non-2xx response so mPDF logs the failure + * and renders a placeholder for the missing image without aborting PDF generation. + * + * @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + */ +final class SafeRemoteContentClient implements ClientInterface +{ + /** + * Timeout in seconds: a slow or unreachable remote target should not block PDF rendering. + */ + private const TIMEOUT = 10; + + public function __construct(private readonly HttpClientInterface $client) + { + } + + public function sendRequest(RequestInterface $request): Response + { + try { + $response = $this->client->request( + $request->getMethod(), + (string) $request->getUri(), + [ + 'headers' => $this->flattenHeaders($request), + 'timeout' => self::TIMEOUT, + 'max_duration' => self::TIMEOUT, + ] + ); + + return new Response( + $response->getStatusCode(), + [], + $response->getContent(false) + ); + } catch (HttpClientExceptionInterface) { + // Request blocked (private network), DNS failure, timeout, etc. + return new Response(502); + } + } + + /** + * @return array + */ + private function flattenHeaders(RequestInterface $request): array + { + $headers = []; + foreach ($request->getHeaders() as $name => $values) { + $headers[$name] = implode(', ', $values); + } + + return $headers; + } +} diff --git a/src/Plugin/PackageManager.php b/src/Plugin/PackageManager.php index be61150e..471dc8d5 100644 --- a/src/Plugin/PackageManager.php +++ b/src/Plugin/PackageManager.php @@ -36,6 +36,10 @@ final class PackageManager */ private function findAvailablePackages(string $path): array { + if (!file_exists($path) || !is_readable($path) || !is_dir($path)) { + return []; + } + $packages = []; $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS); diff --git a/src/Security/RolePermissionManager.php b/src/Security/RolePermissionManager.php index 20b8bcff..3c83090c 100644 --- a/src/Security/RolePermissionManager.php +++ b/src/Security/RolePermissionManager.php @@ -199,7 +199,7 @@ final class RolePermissionManager return $this->checkTeamLeadAccess($timesheet->getUser()?->getTeams() ?? [], $user); } - public function checkUserAccess(User $subject, User $user): bool + public function checkUserAccess(User $subject, User $user, bool $onlyEnabled = true): bool { if ($subject->getId() === $user->getId()) { return true; @@ -209,10 +209,12 @@ final class RolePermissionManager return true; } - if (!$subject->isEnabled()) { + if ($onlyEnabled && !$subject->isEnabled()) { return false; } + // system accounts are used for admins or API-only accounts + // and should not be accessed by less-privileged users (e.g. teamleads) if (!$user->isSystemAccount() && $subject->isSystemAccount()) { return false; } diff --git a/src/Twig/Runtime/MarkdownExtension.php b/src/Twig/Runtime/MarkdownExtension.php index 1752285a..40405ee1 100644 --- a/src/Twig/Runtime/MarkdownExtension.php +++ b/src/Twig/Runtime/MarkdownExtension.php @@ -17,7 +17,10 @@ final class MarkdownExtension implements RuntimeExtensionInterface { private ?bool $markdownEnabled = null; - public function __construct(private Markdown $markdown, private SystemConfiguration $configuration) + public function __construct( + private readonly Markdown $markdown, + private readonly SystemConfiguration $configuration + ) { } @@ -32,10 +35,6 @@ final class MarkdownExtension implements RuntimeExtensionInterface /** * Transforms entity and user comments (customer, project, activity ...) into HTML. - * - * @param string|null $content - * @param bool $fullLength - * @return string */ public function commentContent(?string $content, bool $fullLength = true): string { @@ -58,10 +57,6 @@ final class MarkdownExtension implements RuntimeExtensionInterface /** * Transforms the entities comment (customer, project, activity ...) into a one-liner. - * - * @param string|null $content - * @param bool $fullLength - * @return string */ public function commentOneLiner(?string $content, bool $fullLength = true): string { @@ -88,9 +83,6 @@ final class MarkdownExtension implements RuntimeExtensionInterface /** * Transforms the timesheet description content into HTML. - * - * @param string|null $content - * @return string */ public function timesheetContent(?string $content): string { @@ -107,9 +99,6 @@ final class MarkdownExtension implements RuntimeExtensionInterface /** * Transforms the given Markdown content into HTML - * - * @param string $content - * @return string */ public function markdownToHtml(string $content): string { diff --git a/src/Utils/Markdown.php b/src/Utils/Markdown.php index 362725e3..b0b711b6 100644 --- a/src/Utils/Markdown.php +++ b/src/Utils/Markdown.php @@ -15,7 +15,7 @@ namespace App\Utils; final class Markdown { private ?ParsedownExtension $parser = null; - private ?\Parsedown $parserFull = null; + private ?Parsedown $parserFull = null; public function toHtml(string $text): string { diff --git a/src/Utils/Parsedown.php b/src/Utils/Parsedown.php index bd32e1b2..ea705c66 100644 --- a/src/Utils/Parsedown.php +++ b/src/Utils/Parsedown.php @@ -17,6 +17,20 @@ class Parsedown extends \Parsedown /** @var array */ private array $ids = []; + /** + * Overwritten to open links in new windows + */ + protected function inlineUrl($Excerpt): ?array // @phpstan-ignore missingType.parameter,missingType.iterableValue + { + $block = parent::inlineUrl($Excerpt); + + if (isset($block['element']['attributes']) && \is_array($block['element']['attributes'])) { + $block['element']['attributes']['target'] = '_blank'; + } + + return $block; + } + protected function blockHeader($Line) { $block = parent::blockHeader($Line); @@ -84,4 +98,42 @@ class Parsedown extends \Parsedown return $Block; } + + /** + * Markdown image syntax `![alt](url)` is rewritten to a link `alt`. + * + * Rationale: emitting `` would cause downstream renderers + * (e.g. mPDF on the server, browsers in the UI) to automatically fetch + * the remote URL. For server-side renderers this is a server-side request + * forgery vector; in the UI it is a tracking/privacy issue. Hand-written + * `` in Twig templates (custom invoice templates etc.) is not + * affected — only images derived from Markdown input are neutralised + * here. The resulting `` is still passed through Parsedown's + * `safeLinksWhitelist` filtering when safe-mode is enabled. + * + * @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + */ + protected function inlineImage($Excerpt): ?array // @phpstan-ignore missingType.parameter,missingType.iterableValue + { + $Image = parent::inlineImage($Excerpt); + + if ($Image === null) { + return null; + } + + $src = $Image['element']['attributes']['src'] ?? ''; + $alt = $Image['element']['attributes']['alt'] ?? ''; + + $Image['element'] = [ + 'name' => 'a', + 'text' => $alt !== '' ? $alt : $src, + 'attributes' => [ + 'href' => $src, + 'rel' => 'noopener noreferrer', + 'target' => '_blank', + ], + ]; + + return $Image; + } } diff --git a/src/Utils/ParsedownExtension.php b/src/Utils/ParsedownExtension.php index 17f7dbec..427a086a 100644 --- a/src/Utils/ParsedownExtension.php +++ b/src/Utils/ParsedownExtension.php @@ -10,7 +10,7 @@ namespace App\Utils; /** - * This Class extends the default Parsedown Class for custom methods. + * The default markdown implementation. */ final class ParsedownExtension extends Parsedown { @@ -42,31 +42,4 @@ final class ParsedownExtension extends Parsedown '|' => ['Table'], '~' => ['FencedCode'], ]; - - /** - * Overwritten to open links in new windows - */ - protected function inlineUrl($Excerpt): ?array - { - $block = parent::inlineUrl($Excerpt); - - if (isset($block['element']['attributes']) && \is_array($block['element']['attributes'])) { - $block['element']['attributes']['target'] = '_blank'; - } - - return $block; - } - - protected function blockTable($Line, ?array $Block = null) // @phpstan-ignore missingType.return,missingType.iterableValue,missingType.parameter - { - $Block = parent::blockTable($Line, $Block); - - if ($Block === null) { - return null; - } - - $Block['element']['attributes']['class'] = 'table'; - - return $Block; - } } diff --git a/src/Voter/TimesheetVoter.php b/src/Voter/TimesheetVoter.php index f925ff2c..a4bbbebe 100644 --- a/src/Voter/TimesheetVoter.php +++ b/src/Voter/TimesheetVoter.php @@ -83,7 +83,7 @@ final class TimesheetVoter extends Voter { $user = $token->getUser(); - if (!($user instanceof User)) { + if (!($user instanceof User) || $user->getId() === null) { return false; } @@ -91,10 +91,10 @@ final class TimesheetVoter extends Voter switch ($attribute) { case 'is_owner': - return (!$subject instanceof MultiUserTimesheet) && $user === $subject->getUser(); + return (!$subject instanceof MultiUserTimesheet) && $user->getId() === $subject->getUser()?->getId(); case self::START: - if (!$this->canStart($subject)) { + if (!$this->canStart($user, $subject)) { return false; } $permission .= $attribute; @@ -115,7 +115,7 @@ final class TimesheetVoter extends Voter break; case 'duplicate': - if (!$this->canStart($subject)) { + if (!$this->canStart($user, $subject)) { return false; } $permission = self::EDIT; @@ -146,11 +146,10 @@ final class TimesheetVoter extends Voter return $this->permissionManager->hasRolePermission($user, $permission . '_other_timesheet'); } - private function canStart(Timesheet $timesheet): bool + private function canStart(User $user, Timesheet $timesheet): bool { // possible improvements for the future: // we could check the amount of active entries (maybe slow) - // if a teamlead starts an entry for another user, check that this user is part of his team (needs to be done for teams) if (null === $timesheet->getActivity()) { return false; @@ -172,6 +171,18 @@ final class TimesheetVoter extends Voter return false; } + // starting and duplicating both create a NEW record under the referenced + // project and activity, so the current user must still have team-based + // access to them - historical ownership of the original timesheet is not + // sufficient (otherwise old entries would survive an access revocation). + if (!$this->permissionManager->checkTeamAccessProject($timesheet->getProject(), $user)) { + return false; + } + + if (!$this->permissionManager->checkTeamAccessActivity($timesheet->getActivity(), $user)) { + return false; + } + return true; } diff --git a/src/Voter/UserVoter.php b/src/Voter/UserVoter.php index d644793d..e63073f2 100644 --- a/src/Voter/UserVoter.php +++ b/src/Voter/UserVoter.php @@ -62,11 +62,7 @@ final class UserVoter extends Voter { $user = $token->getUser(); - if (!($user instanceof User)) { - return false; - } - - if (!($subject instanceof User)) { + if (!($user instanceof User) || !($subject instanceof User)) { return false; } @@ -111,15 +107,14 @@ final class UserVoter extends Voter $permission = $attribute; - // extend me for "team" support later on if ($subject->getId() === $user->getId()) { - $permission .= '_own'; - } else { - $permission .= '_other'; + return $this->permissionManager->hasRolePermission($user, $permission . '_own_profile'); } - $permission .= '_profile'; + if (!$this->permissionManager->hasRolePermission($user, $permission . '_other_profile')) { + return false; + } - return $this->permissionManager->hasRolePermission($user, $permission); + return $this->permissionManager->checkUserAccess($subject, $user, false); } } diff --git a/templates/activity/details.html.twig b/templates/activity/details.html.twig index 5efa33db..ee652997 100644 --- a/templates/activity/details.html.twig +++ b/templates/activity/details.html.twig @@ -107,7 +107,7 @@ {% if teams is not null %} {% set options = {'teams': teams, 'team': team} %} {% if is_granted('permissions', activity) %} - {% set options = options|merge({'route_create': path('activity_team_create', {'id': activity.id}), 'route_edit': path('admin_activity_permissions', {'id': activity.id})}) %} + {% set options = options|merge({'route_create': path('post_activity_team', {'id': activity.id}), 'route_edit': path('admin_activity_permissions', {'id': activity.id})}) %} {% endif %} {% if activity.project is not null and (activity.project.teams|length > 0 or activity.project.customer.teams|length > 0) %} {% set options = options|merge({'empty_message': 'team.activity_visibility_inherited'}) %} diff --git a/templates/customer/details.html.twig b/templates/customer/details.html.twig index 05b00c37..51741ad3 100644 --- a/templates/customer/details.html.twig +++ b/templates/customer/details.html.twig @@ -159,7 +159,7 @@ {% if teams is not null %} {% set options = {'teams': teams, 'team': team} %} {% if is_granted('permissions', customer) %} - {% set options = options|merge({'route_create': path('customer_team_create', {'id': customer.id}), 'route_edit': path('admin_customer_permissions', {'id': customer.id})}) %} + {% set options = options|merge({'route_create': path('post_customer_team', {'id': customer.id}), 'route_edit': path('admin_customer_permissions', {'id': customer.id})}) %} {% endif %} {{ include('embeds/teams.html.twig', options) }} {% endif %} diff --git a/templates/embeds/rates-table.html.twig b/templates/embeds/rates-table.html.twig index 424a888b..96b9f379 100644 --- a/templates/embeds/rates-table.html.twig +++ b/templates/embeds/rates-table.html.twig @@ -56,7 +56,7 @@ diff --git a/templates/embeds/teams.html.twig b/templates/embeds/teams.html.twig index 793793d4..69e450e6 100644 --- a/templates/embeds/teams.html.twig +++ b/templates/embeds/teams.html.twig @@ -1,17 +1,28 @@ -{% +{% set options = { - 'teams': teams, - 'team': team|default(null), - 'route_create': route_create|default(null), - 'route_edit': route_edit|default(null), + 'teams': teams, + 'team': team|default(null), + 'route_create': route_create|default(null), + 'route_edit': route_edit|default(null), 'empty_message': empty_message|default('team.visibility_global') - } + } %} {% embed '@theme/embeds/card.html.twig' with options %} {% import "macros/widgets.html.twig" as widgets %} {% block box_tools %} {% if route_create is not null and (teams|length == 0 or team is null) and is_granted('create_team') %} - {{ widgets.card_tool_button('create', {'title': 'team.create_default', 'translation_domain': 'teams', 'url': route_create}) }} + {{ widgets.card_tool_button('create', { + 'title': 'team.create_default', + 'translation_domain': 'teams', + 'url': '#', + 'class': 'api-link', + 'attr': { + 'data-href': route_create, + 'data-method': 'POST', + 'data-event': 'kimai.teamUpdate', + 'data-msg-error': 'action.update.error' + } + }) }} {% endif %} {% if route_edit is not null %} {{ widgets.card_tool_button('edit', {'class': 'modal-ajax-form open-edit', 'title': 'edit', 'url': route_edit}) }} diff --git a/templates/favorite/index.html.twig b/templates/favorite/index.html.twig index b5e4a94e..891981c2 100644 --- a/templates/favorite/index.html.twig +++ b/templates/favorite/index.html.twig @@ -10,7 +10,7 @@
- {{ label_activity(entry.activity) }} diff --git a/templates/project/details.html.twig b/templates/project/details.html.twig index e7911b02..99088714 100644 --- a/templates/project/details.html.twig +++ b/templates/project/details.html.twig @@ -154,7 +154,7 @@ {% if teams is not null%} {% set options = {'teams': teams, 'team': team} %} {% if is_granted('permissions', project) %} - {% set options = options|merge({'route_create': path('project_team_create', {'id': project.id}), 'route_edit': path('admin_project_permissions', {'id': project.id})}) %} + {% set options = options|merge({'route_create': path('post_project_team', {'id': project.id}), 'route_edit': path('admin_project_permissions', {'id': project.id})}) %} {% endif %} {% if project.customer.teams|length > 0 %} {% set options = options|merge({'empty_message': 'team.project_visibility_inherited'}) %} diff --git a/templates/wizard/done.html.twig b/templates/wizard/done.html.twig index 2310981b..f8bf1542 100644 --- a/templates/wizard/done.html.twig +++ b/templates/wizard/done.html.twig @@ -3,7 +3,7 @@ {% block wizard_content %}
- Illustration by Katerina Limpitsouni from https://undraw.co/ + Illustration by Katerina Limpitsouni from https://undraw.co/

{{ 'wizard.done.title'|trans({}, 'wizard') }}

{{ 'wizard.done.description'|trans({}, 'wizard') }}

diff --git a/templates/wizard/intro.html.twig b/templates/wizard/intro.html.twig index 5d0d44d8..558da70a 100644 --- a/templates/wizard/intro.html.twig +++ b/templates/wizard/intro.html.twig @@ -2,7 +2,7 @@ {% block wizard_content %}
- Illustration by Katerina Limpitsouni from https://undraw.co/ + Illustration by Katerina Limpitsouni from https://undraw.co/

{{ 'wizard.intro.title'|trans({}, 'wizard') }}

{{ 'wizard.intro.description'|trans({}, 'wizard') }}

diff --git a/tests/API/ActivityControllerTest.php b/tests/API/ActivityControllerTest.php index 4fe1bdf8..7a5f1c34 100644 --- a/tests/API/ActivityControllerTest.php +++ b/tests/API/ActivityControllerTest.php @@ -559,4 +559,49 @@ class ActivityControllerTest extends APIControllerBaseTestCase 'message' => 'Not Found' ]); } + + public function testPostDefaultTeamAction(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + + $this->request($client, '/api/activities/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertApiResponseTypeStructure('TeamEntity', $result); + self::assertIsNumeric($result['id']); + $teamId = $result['id']; + + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + self::assertIsArray($result['members'][0]); + self::assertArrayHasKey('teamlead', $result['members'][0]); + self::assertTrue($result['members'][0]['teamlead']); + + // idempotent + $this->request($client, '/api/activities/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertSame($teamId, $result['id']); + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + } + + public function testPostDefaultTeamActionIsSecure(): void + { + $this->assertUrlIsSecuredForRole(User::ROLE_USER, '/api/activities/1/team', 'POST'); + } + + public function testPostDefaultTeamActionNotFound(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + $this->assertEntityNotFoundForPost($client, '/api/activities/' . PHP_INT_MAX . '/team'); + } } diff --git a/tests/API/ApiDocControllerTest.php b/tests/API/ApiDocControllerTest.php index 98ae0d46..0d9d18d3 100644 --- a/tests/API/ApiDocControllerTest.php +++ b/tests/API/ApiDocControllerTest.php @@ -66,6 +66,7 @@ class ApiDocControllerTest extends AbstractControllerBaseTestCase '/api/activities/{id}/meta', '/api/activities/{id}/rates', '/api/activities/{id}/rates/{rateId}', + '/api/activities/{id}/team', '/api/config/timesheet', '/api/config/colors', '/api/customers', @@ -76,6 +77,7 @@ class ApiDocControllerTest extends AbstractControllerBaseTestCase '/api/customers/{id}/comments', '/api/customers/{id}/comments/{comment}/pin', '/api/customers/{id}/comments/{comment}', + '/api/customers/{id}/team', '/api/export/{id}', '/api/invoices', '/api/invoices/{id}', @@ -89,6 +91,7 @@ class ApiDocControllerTest extends AbstractControllerBaseTestCase '/api/projects/{id}/comments', '/api/projects/{id}/comments/{comment}/pin', '/api/projects/{id}/comments/{comment}', + '/api/projects/{id}/team', '/api/ping', '/api/version', '/api/plugins', diff --git a/tests/API/CustomerControllerTest.php b/tests/API/CustomerControllerTest.php index 59fa4768..edd4fb0f 100644 --- a/tests/API/CustomerControllerTest.php +++ b/tests/API/CustomerControllerTest.php @@ -874,4 +874,50 @@ class CustomerControllerTest extends APIControllerBaseTestCase self::assertNull($this->getEntityManager()->getRepository(CustomerComment::class)->find($commentId)); } + + public function testPostDefaultTeamAction(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + + $this->request($client, '/api/customers/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertApiResponseTypeStructure('TeamEntity', $result); + self::assertIsNumeric($result['id']); + $teamId = $result['id']; + + // verify customer is bound and current user is teamlead + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + self::assertIsArray($result['members'][0]); + self::assertArrayHasKey('teamlead', $result['members'][0]); + self::assertTrue($result['members'][0]['teamlead']); + + // idempotent: calling again returns the same team without duplicate bindings or members + $this->request($client, '/api/customers/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertSame($teamId, $result['id']); + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + } + + public function testPostDefaultTeamActionIsSecure(): void + { + $this->assertUrlIsSecuredForRole(User::ROLE_USER, '/api/customers/1/team', 'POST'); + } + + public function testPostDefaultTeamActionNotFound(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + $this->assertEntityNotFoundForPost($client, '/api/customers/' . PHP_INT_MAX . '/team'); + } } diff --git a/tests/API/ProjectControllerTest.php b/tests/API/ProjectControllerTest.php index db3f1b69..e7194664 100644 --- a/tests/API/ProjectControllerTest.php +++ b/tests/API/ProjectControllerTest.php @@ -983,4 +983,49 @@ class ProjectControllerTest extends APIControllerBaseTestCase self::assertNull($this->getEntityManager()->getRepository(ProjectComment::class)->find($commentId)); } + + public function testPostDefaultTeamAction(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + + $this->request($client, '/api/projects/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertApiResponseTypeStructure('TeamEntity', $result); + self::assertIsNumeric($result['id']); + $teamId = $result['id']; + + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + self::assertIsArray($result['members'][0]); + self::assertArrayHasKey('teamlead', $result['members'][0]); + self::assertTrue($result['members'][0]['teamlead']); + + // idempotent + $this->request($client, '/api/projects/1/team', 'POST'); + self::assertTrue($client->getResponse()->isSuccessful()); + + $content = $client->getResponse()->getContent(); + self::assertIsString($content); + $result = json_decode($content, true); + self::assertIsArray($result); + self::assertSame($teamId, $result['id']); + self::assertIsArray($result['members']); + self::assertCount(1, $result['members']); + } + + public function testPostDefaultTeamActionIsSecure(): void + { + $this->assertUrlIsSecuredForRole(User::ROLE_USER, '/api/projects/1/team', 'POST'); + } + + public function testPostDefaultTeamActionNotFound(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); + $this->assertEntityNotFoundForPost($client, '/api/projects/' . PHP_INT_MAX . '/team'); + } } diff --git a/tests/API/TeamControllerTest.php b/tests/API/TeamControllerTest.php index ba010510..0cedad8b 100644 --- a/tests/API/TeamControllerTest.php +++ b/tests/API/TeamControllerTest.php @@ -9,9 +9,16 @@ namespace App\Tests\API; +use App\DataFixtures\UserFixtures; +use App\Entity\Activity; +use App\Entity\Customer; +use App\Entity\Project; +use App\Entity\Role; +use App\Entity\RolePermission; use App\Entity\Team; use App\Entity\User; use App\Tests\DataFixtures\TeamFixtures; +use App\User\PermissionService; use Doctrine\ORM\EntityManager; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; @@ -778,4 +785,334 @@ class TeamControllerTest extends APIControllerBaseTestCase // cannot remove activity $this->assertBadRequest($client, '/api/teams/' . $result['id'] . '/activities/1', 'DELETE'); } + + /** + * Sets up tony_teamlead so that he has the `edit_team` permission via a + * dedicated test role, and makes him the teamlead of a fresh team. + * + * This simulates an installation that lets teamleads manage their own + * teams. The permission is routed through PermissionService so the shared + * cache is invalidated and the request kernel sees the new permission. + * + * @return Team the team the attacker is teamlead of + */ + private function prepareAttackerTeamleadWithEditTeam(string $suffix): Team + { + $em = $this->getEntityManager(); + + $roleName = 'TEST_EDIT_TEAM_' . $suffix; + $role = (new Role())->setName($roleName); + $permission = (new RolePermission())->setRole($role)->setPermission('edit_team')->setAllowed(true); + $em->persist($role); + $p = self::getContainer()->get(PermissionService::class); + self::assertInstanceOf(PermissionService::class, $p); + $p->saveRolePermission($permission); + + $attacker = $this->getUserByName(UserFixtures::USERNAME_TEAMLEAD); + $attacker->addRole($roleName); + $em->persist($attacker); + + $attackerTeam = new Team('GHSA-xv4r attacker team ' . $suffix); + $attackerTeam->addTeamlead($attacker); + $em->persist($attackerTeam); + + $em->flush(); + + return $attackerTeam; + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg. + * + * A teamlead with edit_team permission must not be able to add a user + * that falls outside their authorized management scope by calling the + * member-assignment API directly. The frontend hides those users; the + * backend has to enforce the same boundary. + */ + public function testPostMemberActionDeniesUserOutsideTeamleadScope(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + $attackerTeam = $this->prepareAttackerTeamleadWithEditTeam('GHSA_XV4R_MEMBER'); + + // target user is in a separate team that the attacker has no role in, + // and the target is not a "regular-user-only without any teams" (which + // would otherwise be visible to any teamlead). + $target = $this->getUserByName(UserFixtures::USERNAME_USER); + $isolatedTeam = new Team('GHSA-xv4r isolated team'); + $isolatedTeam->addUser($target); + $isolatedTeam->addTeamlead($this->getUserByRole(User::ROLE_SUPER_ADMIN)); + $em->persist($isolatedTeam); + $em->flush(); + + $teamId = $attackerTeam->getId(); + $targetId = $target->getId(); + self::assertIsInt($teamId); + self::assertIsInt($targetId); + + $this->request($client, '/api/teams/' . $teamId . '/members/' . $targetId, 'POST'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + // verify the relation was NOT persisted + $em->clear(); + $reloaded = $em->getRepository(Team::class)->find($teamId); + self::assertInstanceOf(Team::class, $reloaded); + self::assertFalse($reloaded->hasUser($target)); + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg. + * + * The teamlead must not be able to attach an activity that they cannot + * view in the first place, even when they may edit the team. + */ + public function testPostActivityActionDeniesActivityOutsideTeamleadScope(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + $attackerTeam = $this->prepareAttackerTeamleadWithEditTeam('GHSA_XV4R_ACTIVITY'); + + // activity is created without any team relation that the attacker is part of + $customer = new Customer('GHSA-xv4r activity customer'); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); + $em->persist($customer); + + $project = new Project(); + $project->setName('GHSA-xv4r activity project'); + $project->setCustomer($customer); + $em->persist($project); + + $activity = new Activity(); + $activity->setName('GHSA-xv4r out-of-scope activity'); + $activity->setProject($project); + $em->persist($activity); + + $em->flush(); + + $teamId = $attackerTeam->getId(); + $activityId = $activity->getId(); + self::assertIsInt($teamId); + self::assertIsInt($activityId); + + $this->request($client, '/api/teams/' . $teamId . '/activities/' . $activityId, 'POST'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + $em->clear(); + $reloaded = $em->getRepository(Team::class)->find($teamId); + self::assertInstanceOf(Team::class, $reloaded); + $reloadedActivity = $em->getRepository(Activity::class)->find($activityId); + self::assertInstanceOf(Activity::class, $reloadedActivity); + self::assertFalse($reloaded->hasActivity($reloadedActivity)); + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg (postCustomerAction variant). + * + * A teamlead with edit_team permission must not be able to grant their + * team access to a customer that they cannot view themselves. The bug + * pattern is identical to the postActivityAction variant. + */ + public function testPostCustomerActionDeniesCustomerOutsideTeamleadScope(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + $attackerTeam = $this->prepareAttackerTeamleadWithEditTeam('GHSA_XV4R_CUSTOMER'); + + // customer has no team relation to the attacker -> attacker has no view permission on it + $customer = new Customer('GHSA-xv4r out-of-scope customer'); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); + $em->persist($customer); + $em->flush(); + + $teamId = $attackerTeam->getId(); + $customerId = $customer->getId(); + self::assertIsInt($teamId); + self::assertIsInt($customerId); + + $this->request($client, '/api/teams/' . $teamId . '/customers/' . $customerId, 'POST'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + $em->clear(); + $reloaded = $em->getRepository(Team::class)->find($teamId); + self::assertInstanceOf(Team::class, $reloaded); + $reloadedCustomer = $em->getRepository(Customer::class)->find($customerId); + self::assertInstanceOf(Customer::class, $reloadedCustomer); + self::assertFalse($reloaded->hasCustomer($reloadedCustomer)); + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg (postProjectAction variant). + * + * A teamlead with edit_team permission must not be able to grant their + * team access to a project that they cannot view themselves. + */ + public function testPostProjectActionDeniesProjectOutsideTeamleadScope(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + $attackerTeam = $this->prepareAttackerTeamleadWithEditTeam('GHSA_XV4R_PROJECT'); + + $customer = new Customer('GHSA-xv4r project customer'); + $customer->setCountry('DE'); + $customer->setTimezone('Europe/Berlin'); + $em->persist($customer); + + $project = new Project(); + $project->setName('GHSA-xv4r out-of-scope project'); + $project->setCustomer($customer); + $em->persist($project); + $em->flush(); + + $teamId = $attackerTeam->getId(); + $projectId = $project->getId(); + self::assertIsInt($teamId); + self::assertIsInt($projectId); + + $this->request($client, '/api/teams/' . $teamId . '/projects/' . $projectId, 'POST'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + $em->clear(); + $reloaded = $em->getRepository(Team::class)->find($teamId); + self::assertInstanceOf(Team::class, $reloaded); + $reloadedProject = $em->getRepository(Project::class)->find($projectId); + self::assertInstanceOf(Project::class, $reloadedProject); + self::assertFalse($reloaded->hasProject($reloadedProject)); + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg (patchAction variant). + * + * The PATCH /api/teams/{id} endpoint takes a `members` array and replaces + * the team's membership. A teamlead with edit_team permission must not be + * able to attach an out-of-scope user this way. + */ + public function testPatchActionDeniesAddingOutOfScopeMember(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + $attackerTeam = $this->prepareAttackerTeamleadWithEditTeam('GHSA_XV4R_PATCH'); + + $attacker = $this->getUserByName(UserFixtures::USERNAME_TEAMLEAD); + $attackerId = $attacker->getId(); + self::assertIsInt($attackerId); + + // target user kept out of attacker's reach + $target = $this->getUserByName(UserFixtures::USERNAME_USER); + $isolatedTeam = new Team('GHSA-xv4r isolated team patch'); + $isolatedTeam->addUser($target); + $isolatedTeam->addTeamlead($this->getUserByRole(User::ROLE_SUPER_ADMIN)); + $em->persist($isolatedTeam); + $em->flush(); + + $teamId = $attackerTeam->getId(); + $targetId = $target->getId(); + self::assertIsInt($teamId); + self::assertIsInt($targetId); + + $payload = [ + 'name' => 'GHSA-xv4r patch team', + 'members' => [ + ['user' => $attackerId, 'teamlead' => true], + ['user' => $targetId, 'teamlead' => false], + ], + ]; + + $this->request($client, '/api/teams/' . $teamId, 'PATCH', [], json_encode($payload)); + + $response = $client->getResponse(); + // either a hard 403 or a validation rejection of the members field is acceptable; + // any 2xx that ends with the target attached to the team is the security failure. + self::assertFalse( + $response->isSuccessful() && str_contains((string) $response->getContent(), '"id"'), + 'PATCH /api/teams must not silently attach an out-of-scope user via the members array.' + ); + + $em->clear(); + $reloaded = $em->getRepository(Team::class)->find($teamId); + self::assertInstanceOf(Team::class, $reloaded); + self::assertFalse( + $reloaded->hasUser($target), + 'Out-of-scope user must not have been added to the team via PATCH.' + ); + } + + /** + * Regression test for GHSA-xv4r-4885-gwpg (postAction variant). + * + * The POST /api/teams endpoint accepts a `members` array. A user whose + * role grants `create_team` but not `view_all_data` must not be able to + * create a team with members they cannot manage. This covers the + * non-admin "team creator" role configuration. + */ + public function testPostActionDeniesCreatingTeamWithOutOfScopeMember(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + $em = $this->getEntityManager(); + + // grant create_team to a custom role and attach it to tony_teamlead + $roleName = 'TEST_CREATE_TEAM_GHSA_XV4R'; + $role = (new Role())->setName($roleName); + $permission = (new RolePermission())->setRole($role)->setPermission('create_team')->setAllowed(true); + $em->persist($role); + $p = self::getContainer()->get(PermissionService::class); + self::assertInstanceOf(PermissionService::class, $p); + $p->saveRolePermission($permission); + + $attacker = $this->getUserByName(UserFixtures::USERNAME_TEAMLEAD); + $attacker->addRole($roleName); + $em->persist($attacker); + + $attackerId = $attacker->getId(); + self::assertIsInt($attackerId); + + // target user is unreachable for the attacker + $target = $this->getUserByName(UserFixtures::USERNAME_USER); + $isolatedTeam = new Team('GHSA-xv4r isolated team create'); + $isolatedTeam->addUser($target); + $isolatedTeam->addTeamlead($this->getUserByRole(User::ROLE_SUPER_ADMIN)); + $em->persist($isolatedTeam); + $em->flush(); + + $targetId = $target->getId(); + self::assertIsInt($targetId); + + $payload = [ + 'name' => 'GHSA-xv4r created team', + 'members' => [ + ['user' => $attackerId, 'teamlead' => true], + ['user' => $targetId, 'teamlead' => false], + ], + ]; + + $this->request($client, '/api/teams', 'POST', [], json_encode($payload)); + + $response = $client->getResponse(); + $body = (string) $response->getContent(); + + // success body would contain the new id and the target as a member -> security failure + if ($response->isSuccessful()) { + $decoded = json_decode($body, true); + self::assertIsArray($decoded); + $memberIds = []; + if (\is_array($decoded['members'] ?? null)) { + foreach ($decoded['members'] as $entry) { + if (\is_array($entry) && \is_array($entry['user'] ?? null) && isset($entry['user']['id'])) { + $memberIds[] = $entry['user']['id']; + } + } + } + self::assertNotContains( + $targetId, + $memberIds, + 'POST /api/teams must not silently accept an out-of-scope user in the members array.' + ); + } + } } diff --git a/tests/API/TimesheetControllerTest.php b/tests/API/TimesheetControllerTest.php index 2f5afa1b..23881b23 100644 --- a/tests/API/TimesheetControllerTest.php +++ b/tests/API/TimesheetControllerTest.php @@ -1528,6 +1528,72 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $this->assertEntityNotFoundForPatch(User::ROLE_ADMIN, '/api/timesheets/11/duplicate', []); } + // ------------------------------------------------------------------ + // GHSA-c6w6-57jj-62vh — restart/duplicate after project access revocation. + // + // "restart" and "duplicate" derive a NEW timesheet from a historical + // entry the user still owns. Once the user's team access to the underlying + // project/activity is revoked, neither operation may create a new record + // under it. The data write itself is already blocked by + // TimesheetTeamAccessValidator (since 2.57); these tests additionally pin + // that the TimesheetVoter denies the request at the authorization layer — + // a clean 403, not an incidental 400 from downstream validation. + // ------------------------------------------------------------------ + + public function testRestartAndDuplicateDeniedAfterProjectAccessRevoked(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); + $em = $this->getEntityManager(); + $owner = $this->getUserByRole(User::ROLE_USER); + + // The customer is restricted to a team the user is NOT a member of: + // the user's access to this project/activity has been revoked, but + // their historical timesheet still references it. + $revokedTeam = new Team('GHSA-c6w6 team without access'); + $em->persist($revokedTeam); + + $timesheet = $this->persistRestrictedTimesheet($owner, [$revokedTeam], running: false); + $id = $timesheet->getId(); + self::assertIsInt($id); + + $before = $this->getEntityManager()->getRepository(Timesheet::class)->count([]); + + // PATCH + GET .../restart + $this->request($client, '/api/timesheets/' . $id . '/restart', 'PATCH'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + // PATCH .../duplicate + $this->request($client, '/api/timesheets/' . $id . '/duplicate', 'PATCH'); + $this->assertApiResponseAccessDenied($client->getResponse()); + + // No new record may have been persisted under the revoked project. + $after = $this->getEntityManager()->getRepository(Timesheet::class)->count([]); + self::assertSame($before, $after, 'restart/duplicate leaked through and created a new timesheet under the revoked project'); + } + + public function testRestartAndDuplicateAllowedWhenUserStillHasProjectAccess(): void + { + // Positive control: as long as the user still has team access to the + // project/activity, restart and duplicate keep working. + $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); + $em = $this->getEntityManager(); + $owner = $this->getUserByRole(User::ROLE_USER); + + $team = new Team('GHSA-c6w6 team with access'); + $team->addUser($owner); + $em->persist($team); + + $timesheet = $this->persistRestrictedTimesheet($owner, [$team], running: false); + $id = $timesheet->getId(); + self::assertIsInt($id); + + $this->request($client, '/api/timesheets/' . $id . '/restart', 'PATCH'); + self::assertTrue($client->getResponse()->isSuccessful(), 'restart must succeed while the user still has project access'); + + $this->request($client, '/api/timesheets/' . $id . '/duplicate', 'PATCH'); + self::assertTrue($client->getResponse()->isSuccessful(), 'duplicate must succeed while the user still has project access'); + } + public function testExportAction(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); @@ -1695,17 +1761,17 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $this->request($client, '/api/timesheets/' . $id, 'PATCH', [], $patch); $this->assertApiResponseAccessDenied($client->getResponse()); - // 3) PATCH /api/timesheets/{id}/stop and 4) GET .../stop + // 3) PATCH /api/timesheets/{id}/stop is access-denied; 4) GET .../stop is no longer routable $this->request($client, '/api/timesheets/' . $id . '/stop', 'PATCH'); $this->assertApiResponseAccessDenied($client->getResponse()); $this->request($client, '/api/timesheets/' . $id . '/stop', 'GET'); - $this->assertApiResponseAccessDenied($client->getResponse()); + self::assertEquals(Response::HTTP_METHOD_NOT_ALLOWED, $client->getResponse()->getStatusCode()); - // 5) PATCH /api/timesheets/{id}/restart and 6) GET .../restart + // 5) PATCH /api/timesheets/{id}/restart is access-denied; 6) GET .../restart is no longer routable $this->request($client, '/api/timesheets/' . $id . '/restart', 'PATCH'); $this->assertApiResponseAccessDenied($client->getResponse()); $this->request($client, '/api/timesheets/' . $id . '/restart', 'GET'); - $this->assertApiResponseAccessDenied($client->getResponse()); + self::assertEquals(Response::HTTP_METHOD_NOT_ALLOWED, $client->getResponse()->getStatusCode()); // 7) PATCH /api/timesheets/{id}/duplicate $this->request($client, '/api/timesheets/' . $id . '/duplicate', 'PATCH'); @@ -1931,7 +1997,7 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $this->assertApiResponseAccessDenied($client->getResponse()); $this->request($client, '/api/timesheets/' . $id . '/stop', 'GET'); - $this->assertApiResponseAccessDenied($client->getResponse()); + self::assertEquals(Response::HTTP_METHOD_NOT_ALLOWED, $client->getResponse()->getStatusCode()); // Confirm side-effect-free: timesheet must still be running. $em->clear(); diff --git a/tests/Controller/ActivityControllerTest.php b/tests/Controller/ActivityControllerTest.php index 061d4167..d4b44270 100644 --- a/tests/Controller/ActivityControllerTest.php +++ b/tests/Controller/ActivityControllerTest.php @@ -350,22 +350,6 @@ class ActivityControllerTest extends AbstractControllerBaseTestCase self::assertEquals(2, $activity->getTeams()->count()); } - public function testCreateDefaultTeamAction(): void - { - $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); - $this->assertAccessIsGranted($client, '/admin/activity/1/details'); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-body'); - self::assertStringContainsString('Visible to everyone, as no team was assigned yet.', $node->text()); - - $this->request($client, '/admin/activity/1/create_team'); - $this->assertIsRedirect($client, $this->createUrl('/admin/activity/1/details')); - $client->followRedirect(); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-title'); - self::assertStringContainsString('Only visible to the following teams and all admins.', $node->text()); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-body table tbody tr'); - self::assertEquals(1, $node->count()); - } - public function testDeleteAction(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); diff --git a/tests/Controller/CustomerControllerTest.php b/tests/Controller/CustomerControllerTest.php index 5542dc57..e44c8be6 100644 --- a/tests/Controller/CustomerControllerTest.php +++ b/tests/Controller/CustomerControllerTest.php @@ -216,22 +216,6 @@ class CustomerControllerTest extends AbstractControllerBaseTestCase self::assertStringContainsString('

A beautiful and short comment with some markdown formatting

', $node->html()); } - public function testCreateDefaultTeamAction(): void - { - $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); - $this->assertAccessIsGranted($client, '/admin/customer/1/details'); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-body'); - self::assertStringContainsString('Visible to everyone, as no team was assigned yet.', $node->text(null, true)); - - $this->request($client, '/admin/customer/1/create_team'); - $this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details')); - $client->followRedirect(); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-title'); - self::assertStringContainsString('Only visible to the following teams and all admins.', $node->text(null, true)); - $node = $client->getCrawler()->filter('div.card#team_listing_box .card-body table tbody tr'); - self::assertEquals(1, $node->count()); - } - public function testProjectsAction(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); diff --git a/tests/Controller/ExportControllerTest.php b/tests/Controller/ExportControllerTest.php index c5dc3717..5e4d25f4 100644 --- a/tests/Controller/ExportControllerTest.php +++ b/tests/Controller/ExportControllerTest.php @@ -265,6 +265,24 @@ class ExportControllerTest extends AbstractControllerBaseTestCase $this->assertUrlIsSecuredForRole(User::ROLE_USER, '/export/template-create'); } + public function testCreateTemplateIsSecureForTeamlead(): void + { + // GHSA-rw46-qg69-vg6h + $this->assertUrlIsSecuredForRole(User::ROLE_TEAMLEAD, '/export/template-create'); + } + + public function testEditTemplateIsSecureForTeamlead(): void + { + // GHSA-rw46-qg69-vg6h + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + /** @var ExportTemplate[] $templates */ + $templates = $this->importFixture(new ExportTemplateFixtures()); + $id = $templates[0]->getId(); + + $this->request($client, $this->createUrl('/export/template-edit/' . $id)); + $this->assertAccessDenied($client); + } + public function testCreateTemplateAction(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); diff --git a/tests/Controller/FavoriteControllerTest.php b/tests/Controller/FavoriteControllerTest.php index a11ac155..4e5f9b5e 100644 --- a/tests/Controller/FavoriteControllerTest.php +++ b/tests/Controller/FavoriteControllerTest.php @@ -40,7 +40,8 @@ class FavoriteControllerTest extends AbstractControllerBaseTestCase $content = $client->getResponse()->getContent(); self::assertNotFalse($content); - self::assertStringContainsString('
createSut(); + + $subject = self::userWithId(1); + $subject->setEnabled(false); + (new Team('Subject team'))->addUser($subject); + + $requester = self::userWithId(2); + $requester->setRoles([User::ROLE_TEAMLEAD]); + + self::assertFalse($sut->checkUserAccess($subject, $requester, false)); + } + + public function testCheckUserAccessOnlyEnabledFalseStillBlocksSystemAccountSubject(): void + { + // the system-account guard sits below the "enabled" check, so it must still + // apply when $onlyEnabled = false. + $sut = $this->createSut(); + + $subject = self::userWithId(1); + $subject->setEnabled(false); + $subject->setSystemAccount(true); + + $requester = self::userWithId(2); + $team = new Team('Support'); + $team->addUser($subject); + $team->addTeamlead($requester); + + self::assertFalse($sut->checkUserAccess($subject, $requester, false)); + } + + public function testCheckUserAccessOnlyEnabledFalseGrantsAdminFallbackForDisabledTeamlessUser(): void + { + $sut = $this->createSut(); + + $subject = self::userWithId(1); + $subject->setEnabled(false); + + $requester = self::userWithId(2); + $requester->setRoles([User::ROLE_ADMIN]); + + self::assertTrue($subject->isRegularUserOnly()); + self::assertSame([], $subject->getTeams()); + self::assertFalse($sut->checkUserAccess($subject, $requester)); + self::assertTrue($sut->checkUserAccess($subject, $requester, false)); + } + + public function testCheckUserAccessOnlyEnabledFalseStillGrantsSuperAdmin(): void + { + // super-admin / canSeeAllData is decided before the "enabled" check, + // so the result must not change with the flag. + $sut = $this->createSut(); + + $subject = self::userWithId(1); + $subject->setEnabled(false); + + $requester = self::userWithId(2); + $requester->setSuperAdmin(true); + + self::assertTrue($sut->checkUserAccess($subject, $requester)); + self::assertTrue($sut->checkUserAccess($subject, $requester, false)); + } + public function testCheckUserAccessDeniesSystemAccountForNonSystemRequester(): void { $sut = $this->createSut(); diff --git a/tests/Utils/ParsedownExtensionTest.php b/tests/Utils/ParsedownExtensionTest.php index 52e7dfcc..0e5fb300 100644 --- a/tests/Utils/ParsedownExtensionTest.php +++ b/tests/Utils/ParsedownExtensionTest.php @@ -28,7 +28,7 @@ class ParsedownExtensionTest extends TestCase | Another entry | € 111 | | | | | Total | A lot |'); - self::assertStringStartsWith('', $html); + self::assertStringStartsWith('
', $html); } public function testHeaderIsNotConverted(): void @@ -39,4 +39,23 @@ class ParsedownExtensionTest extends TestCase '); self::assertEquals('

# Foo

', $html); } + + /** + * Markdown image syntax must never emit an `` tag, otherwise mPDF + * (server-side) or the browser (UI) would auto-fetch the remote URL. + * + * @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + */ + public function testMarkdownImageIsRewrittenAsLink(): void + { + $sut = new ParsedownExtension(); + $sut->setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text('![probe](http://attacker.example/p.png)'); + + self::assertStringNotContainsString('probe', $html); + } } diff --git a/tests/Utils/ParsedownTest.php b/tests/Utils/ParsedownTest.php index ee41fe04..1e517f22 100644 --- a/tests/Utils/ParsedownTest.php +++ b/tests/Utils/ParsedownTest.php @@ -50,4 +50,74 @@ class ParsedownTest extends TestCase

Foo

Foo

', $html); } + + /** + * Markdown image syntax must never emit an `` tag, otherwise mPDF + * (server-side) or the browser (UI) would auto-fetch the remote URL. + * + * @see https://github.com/kimai/kimai/security/advisories/GHSA-pj8j-p4g4-4vw8 + */ + public function testMarkdownImageIsRewrittenAsLink(): void + { + $sut = new Parsedown(); + $sut->setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text('![probe](http://attacker.example/p.png)'); + + self::assertStringNotContainsString('probe', $html); + self::assertStringContainsString('target="_blank"', $html); + self::assertStringContainsString('rel="noopener noreferrer"', $html); + } + + public function testMarkdownImageWithoutAltUsesUrlAsLabel(): void + { + $sut = new Parsedown(); + $sut->setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text('![](http://attacker.example/p.png)'); + + self::assertStringNotContainsString('http://attacker.example/p.png', $html); + } + + public function testReferenceStyleImageIsRewrittenAsLink(): void + { + $sut = new Parsedown(); + $sut->setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text("![probe][ref]\n\n[ref]: http://attacker.example/p.png"); + + self::assertStringNotContainsString('probe', $html); + } + + public function testRawHtmlImageIsEscaped(): void + { + $sut = new Parsedown(); + $sut->setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text(''); + + self::assertStringNotContainsString('setSafeMode(true); + $sut->setMarkupEscaped(true); + + $html = $sut->text('![x](javascript:alert(1))'); + + self::assertStringNotContainsString('setCustomer($customer); + $project->addTeam($restrictedTeam); + + $activity = new Activity(); + $activity->setProject($project); + + $timesheet = new Timesheet(); + $timesheet->setUser($owner); + $timesheet->setProject($project); + $timesheet->setActivity($activity); + + $this->assertVote($owner, $timesheet, 'start', VoterInterface::ACCESS_DENIED); + $this->assertVote($owner, $timesheet, 'duplicate', VoterInterface::ACCESS_DENIED); + } + + /** + * Reproduces GHSA-c6w6-57jj-62vh for activity-level restriction. + * + * Even if the project is unrestricted, a restricted activity (a team the + * owner is no longer in) must block restart/duplicate. + */ + public function testStartAndDuplicateDeniedAfterActivityAccessRevoked(): void + { + $owner = self::getUser(1, User::ROLE_USER); + + $customer = new Customer('Acme'); + $project = new Project(); + $project->setCustomer($customer); + + $activity = new Activity(); + $activity->setProject($project); + $activity->addTeam(new Team('restricted after revocation')); + + $timesheet = new Timesheet(); + $timesheet->setUser($owner); + $timesheet->setProject($project); + $timesheet->setActivity($activity); + + $this->assertVote($owner, $timesheet, 'start', VoterInterface::ACCESS_DENIED); + $this->assertVote($owner, $timesheet, 'duplicate', VoterInterface::ACCESS_DENIED); + } + + /** + * Positive control for GHSA-c6w6-57jj-62vh: when the owner still has team + * access to the project and activity, restart/duplicate stay allowed. + * Guards the fix against over-restriction. + */ + public function testStartAndDuplicateGrantedWhenOwnerStillHasProjectAccess(): void + { + $owner = self::getUser(1, User::ROLE_USER); + + $team = new Team('still a member'); + $team->addUser($owner); + + $customer = new Customer('Acme'); + $project = new Project(); + $project->setCustomer($customer); + $project->addTeam($team); + + $activity = new Activity(); + $activity->setProject($project); + + $timesheet = new Timesheet(); + $timesheet->setUser($owner); + $timesheet->setProject($project); + $timesheet->setActivity($activity); + + $this->assertVote($owner, $timesheet, 'start', VoterInterface::ACCESS_GRANTED); + $this->assertVote($owner, $timesheet, 'duplicate', VoterInterface::ACCESS_GRANTED); + } + private static function getTimesheetFor(User $owner, ?Team $customerTeam = null, ?Team $projectTeam = null, ?Team $activityTeam = null): Timesheet { $customer = new Customer('Acme'); diff --git a/tests/Voter/UserVoterTest.php b/tests/Voter/UserVoterTest.php index f784b04b..de3696b8 100644 --- a/tests/Voter/UserVoterTest.php +++ b/tests/Voter/UserVoterTest.php @@ -10,6 +10,7 @@ namespace App\Tests\Voter; use App\Entity\InvoiceTemplate; +use App\Entity\Team; use App\Entity\User; use App\Voter\UserVoter; use PHPUnit\Framework\Attributes\CoversClass; @@ -119,4 +120,137 @@ class UserVoterTest extends AbstractVoterTestCase self::assertEquals(VoterInterface::ACCESS_GRANTED, $sut->vote($token, $user, ['view_team_member'])); self::assertEquals(VoterInterface::ACCESS_DENIED, $sut->vote($token, $userMock, ['view_team_member'])); } + + /** + * Even with the "_other_profile" role permission, access to another user's + * profile must additionally pass the team-membership check in + * RolePermissionManager::checkUserAccess(). + */ + public function testOtherProfileRequiresTeamRelation(): void + { + $teamlead = self::getUser(10, User::ROLE_TEAMLEAD); + $teamlead->setEnabled(true); + $foreignUser = self::getUser(11, User::ROLE_USER); + $foreignUser->setEnabled(true); + + // give the foreign user a team that the teamlead is NOT part of, + // so the special "subject has no teams" fallback does not kick in + $team = new Team('foreign team'); + $foreignUser->addTeam($team); + + $permissions = [ + 'ROLE_TEAMLEAD' => ['view_other_profile', 'edit_other_profile'], + ]; + $rpm = $this->getRolePermissionManager($permissions, true); + $voter = new UserVoter($rpm); + + $token = new UsernamePasswordToken($teamlead, 'bar', $teamlead->getRoles()); + + // the role permission "view_other_profile" exists, but the team relation is missing + self::assertEquals(VoterInterface::ACCESS_DENIED, $voter->vote($token, $foreignUser, ['view'])); + self::assertEquals(VoterInterface::ACCESS_DENIED, $voter->vote($token, $foreignUser, ['edit'])); + } + + /** + * Same setup as above, but the current user IS teamlead of one of the subject's + * teams — access should then be granted. + */ + public function testOtherProfileGrantedWhenUserIsTeamleadOfSubject(): void + { + $teamlead = self::getUser(20, User::ROLE_TEAMLEAD); + $teamlead->setEnabled(true); + $member = self::getUser(21, User::ROLE_USER); + $member->setEnabled(true); + + $team = new Team('shared team'); + $team->addUser($member); + $team->addTeamlead($teamlead); + + $permissions = [ + 'ROLE_TEAMLEAD' => ['view_other_profile', 'edit_other_profile'], + ]; + $rpm = $this->getRolePermissionManager($permissions, true); + $voter = new UserVoter($rpm); + + $token = new UsernamePasswordToken($teamlead, 'bar', $teamlead->getRoles()); + + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $member, ['view'])); + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $member, ['edit'])); + } + + /** + * Verify that disabled profiles can still be edited (e.g. to reactivate them or check historic data). + */ + public function testOtherProfileAllowedForDisabledSubject(): void + { + $teamlead = self::getUser(30, User::ROLE_TEAMLEAD); + $teamlead->setEnabled(true); + $member = self::getUser(31, User::ROLE_USER); + $member->setEnabled(false); + + $team = new Team('shared team'); + $team->addUser($member); + $team->addTeamlead($teamlead); + + $permissions = [ + 'ROLE_TEAMLEAD' => ['view_other_profile', 'edit_other_profile'], + ]; + $rpm = $this->getRolePermissionManager($permissions, true); + $voter = new UserVoter($rpm); + + $token = new UsernamePasswordToken($teamlead, 'bar', $teamlead->getRoles()); + + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $member, ['view'])); + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $member, ['edit'])); + } + + /** + * Special case in checkUserAccess(): if the subject has no teams at all and the + * current user is a teamlead/admin, access is granted (small-installation case). + */ + public function testOtherProfileGrantedForTeamlessSubjectWhenUserIsTeamlead(): void + { + $teamlead = self::getUser(40, User::ROLE_TEAMLEAD); + $teamlead->setEnabled(true); + $lonelyUser = self::getUser(41, User::ROLE_USER); + $lonelyUser->setEnabled(true); + + $permissions = [ + 'ROLE_TEAMLEAD' => ['view_other_profile', 'edit_other_profile'], + ]; + $rpm = $this->getRolePermissionManager($permissions, true); + $voter = new UserVoter($rpm); + + $token = new UsernamePasswordToken($teamlead, 'bar', $teamlead->getRoles()); + + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $lonelyUser, ['view'])); + self::assertEquals(VoterInterface::ACCESS_GRANTED, $voter->vote($token, $lonelyUser, ['edit'])); + } + + /** + * Without the role permission "_other_profile" the voter must deny, + * regardless of any team relation between user and subject. + */ + public function testOtherProfileDeniedWithoutRolePermissionEvenWithTeamRelation(): void + { + $teamlead = self::getUser(50, User::ROLE_TEAMLEAD); + $teamlead->setEnabled(true); + $member = self::getUser(51, User::ROLE_USER); + $member->setEnabled(true); + + $team = new Team('shared team'); + $team->addUser($member); + $team->addTeamlead($teamlead); + + // no "view_other_profile" permission for ROLE_TEAMLEAD + $permissions = [ + 'ROLE_TEAMLEAD' => ['view_own_profile'], + ]; + $rpm = $this->getRolePermissionManager($permissions, true); + $voter = new UserVoter($rpm); + + $token = new UsernamePasswordToken($teamlead, 'bar', $teamlead->getRoles()); + + self::assertEquals(VoterInterface::ACCESS_DENIED, $voter->vote($token, $member, ['view'])); + } } diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 0f25a9a6..e76013bb 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -273,7 +273,7 @@ parameters: - message: "#^Parameter \\#5 \\$content of method App\\\\Tests\\\\API\\\\APIControllerBaseTestCase\\:\\:request\\(\\) expects string\\|null, string\\|false given\\.$#" - count: 23 + count: 25 path: API/TeamControllerTest.php -